2009年12月27日
自省
使用 type、st r、dir 和其它内置函数
type 函数返回任意对象的数据类型。在 types 模块中列出了可能的数据类型。这对于处理多种数据类型的帮助者函数非常有用。
>>> type(1)
<type 'int'>
>>> li = []
>>> type(li)
<type 'list'>
str 将数据强制转换为字符串。每种数据类型都可以强制转换为字符串。
>>> str(1) (1)
'1'
>>> horsemen = ['war', 'pestilence', 'famine']
>>> horsemen
['war', 'pestilence', 'famine']
>>> horsemen.append('Powerbuilder')
>>> str(horsemen) (2)
"['war', 'pestilence', 'famine', 'Powerbuilder']"
>>> str(odbchelper) (3)
"<module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'>
>>> str(None) (4)
'None'
Example 4.7. dir 介绍
>>> li = []
>>> dir(li) (1)
['append', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']
>>> d = {}
>>> dir(d) (2)
['clear', 'copy', 'get', 'has_key', 'i tems', 'keys', 'setdefault', 'update', 'values']
>>> import odbchelper
>>> dir(odbchelper) (3)
['__builtins__', '__doc__', '__file__', '__name__', 'bui ldConnectionString']
最后是 callable 函数,它接收任何对象作为参数,如果参数对象是可调用的,
返回 True;否则返回 False。可调用对象包括函数、类方法,甚至类自身 (下一
章将更多的关注类)。
Example 4.8. call abl e 介绍
>>> import string
>>> string.punctuation (1)
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>> string.join (2)
<function join at 00C55A7C>
>>> callable(string.punctuation) (3)
False
>>> callable(string.join) (4)
True
>>> print string.join.__doc__ (5)
- 54 -Dive Into Python http://diveintopython.org/
join(list [,sep]) -> string
Return a string composed of the words in list, with
intervening occurrences of sep. The default separator is a
single space.
(joinfields and join are synonymous)
4.3.3. 内置函数
type、str、dir 和其它的 Python 内置函数都归组到了 __builtin__ (前后分别是双下划线) 这个特殊的模块中。如果有帮助的话,你可以认为 Python 在启动时自动执行了 from __builtin__ import *,此语句将所有的 “内置” 函数导入该命名空间,所以在这个命名空间中可以直接使用这些内置函数。
像这样考虑的好处是,你是可以获取 __builtin__ 模块信息的,并以组的形式访问所有的内置函数和属性。猜到什么了吗,现在我们的 Python 有一个称为info 的函数。自己尝试一下,略看一下结果列表。后面我们将深入到一些更重要的函数。(一些内置的错误类,比如 AttributeError,应该看上去已经很熟悉了。)
Example 4.10. getattr 介绍
>>> li = ["Larry", "Curly"]
>>> li.pop (1)
<built-in method pop of list object at 010DF884>
>>> getattr(li, "pop") (2)
<built-in method pop of list object at 010DF884>
>>> getattr(li, "append")("Moe") (3)
>>> li
["Larry", "Curly", "Moe"]
>>> getattr({}, "clear") (4)
<built-in method clear of dictionary object at 00F113D4>
>>> getattr((), "pop") (5)
Traceback (innermost last):
File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'pop'
4.4.1. 用于模块的 getattr
getattr 不仅仅适用于内置数据类型,也可作用于模块。
Example 4.11. apihelp er.py 中的 getatt r 函数
>>> import odbchelper
>>> odbchelper.buildConnectionString (1)
<function buildConnectionString at 00D18DD4>
>>> getattr(odbchelper, "buildConnectionString") (2)
<function buildConnectionString at 00D18DD4>
>>> object = odbchelper
>>> method = "buildConnectionString"
>>> getattr(object, method) (3)
<function buildConnectionString at 00D18DD4>
>>> type(getattr(object, method)) (4)
<type 'function'>
>>> import types
>>> type(getattr(object, method)) == types.FunctionType
True
>>> callable(getattr(object, method)) (5)
True
(1) 该语句返回 odbchelper 模块中 buildConnectionString 函数的引用,Chapter 2,
第一个 Python 程序 你已经研习过这个方法了。(你看到的这个十六进制地
址是我机器上的;你的输出结果会有所不同。)
(2) 使用 getattr,你能够获得同一函数的同一引用。通常,getattr(object,
"attribute") 等价于 object.attribute。如果 object 是一个模块的话,那么 attribute 可能是定义在模块中的任何东西:函数、类或者全局变量。
(3) 接下来的是你真正用在 info 函数中的东西。object 作为一个参数传递给函数; method 是方法或者函数的名称字符串。
(4) 在这个例子中,method 是函数的名称,通过获取 type 可以进行验证。
(5) 由于 method 是一个函数,所以它是可调用的。4.4.1. 用于模块的 getattr getattr 不仅仅适用于内置数据类型,也可作用于模块。
Example 4.12. 使用 getatt r 创建分发者
import statsout
def output(data, format="text"): (1)
output_function = getattr(statsout, "output_%s" % format) (2)
return output_function(data) (3)
(1) output 函数接收一个必备参数 data,和一个可选参数 format。如果没有指定
format 参数,其缺省值是 text 并完成普通文本输出函数的调用。
(2) 你可以连接 format 参数值和 "output_" 来创建一个函数名称作为参数值,
然后从 statsout 模块中取得该函数。这种方式允许今后很容易地扩展程序
以支持其它的输出格式,而且无需修改分发函数。所要做的仅仅是向
statsout 中添加一个函数,比如 output_pdf,之后只要将 “pdf” 作为 format 的
参数值传递给 output 函数即可。
(3) 现在你可以简单地调用输出函数,就像调用其它函数一样。output_function
变量是指向 statsout 模块中相应函数的引用。
Example 4.13. getatt r 缺省值
import statsout
def output(data, format="text"):
output_function = getattr(statsout, "output_%s" % format, statsout.output_text)
return output_function(data) (1)
(1) 这个函数调用一定可以工作,因为你在调用 getattr 时添加了第三个参数。
第三个参数是一个缺省返回值,如果第二个参数指定的属性或者方法没能
找到,则将返回这个缺省返回值。正如你所看到,getattr 是相当强大的。它是自省的核心,在后面的章节中你将看到它更强大的示例
4.5. 过滤列表
如你所知,Python 具有通过列表解析 (Section 3.6, “ 映射 list” ) 将列表映射到
其它列表的强大能力。这种能力同过滤机制结合使用,使列表中的有些元素
被映射的同时跳过另外一些元素。
过滤列表语法:
[mapping-expression for element in source-list if filter-expression]
这是你所知所爱的列表解析的扩展。前三部分都是相同的;最后一部分,以 if
开头的是过滤器表达式。过滤器表达式可以是返回值为真或者假的任何表达
式 (在 Python 中是几乎任何东西)。任何经过滤器表达式演算值为真的元素都
可以包含在映射中。其它的元素都将忽略,它们不会进入映射表达式,更不
会包含在输出列表中。
Example 4.14. 列表过滤介绍
>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d ", "d"]
>>> [elem for elem in li if len(elem) > 1] (1)
['mpilgrim', 'foo']
>>> [elem for elem in li if elem != "b"] (2)
['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
>>> [elem for elem in li if li.count(elem) == 1] (3)
['a', 'mpilgrim', 'foo', 'c']
(1) 这里的映射表达式很简单 (只是返回每个元素的值),所以请把注意力集中到过滤器表达式上。由于 Python 会遍历整个列表,它将对每个元素执行
过滤器表达式。如果过滤器表达式演算值为真,该元素就会被映射,同时
映射表达式的结果将包含在返回的列表中。这里,你过滤掉了所有单字符
的字符串,留下了一个由长字符串构成的列表。
(2) 这里你过滤掉了一个特定值 b。注意这个过滤器会过滤掉所有的 b,因为每次取出 b,过滤表达式都将为假。
(3) count 是一个列表方法,返回某个值在列表中出现的次数。你可以认为这个过滤器将从列表中剔除重复元素,返回一个只包含了在原始列表中有着
唯一值拷贝的列表。但并非如此,因为在原始列表中出现两次的值 (在本
例中,b 和 d) 被完全剔除了。从一个列表中排除重复值有多种方法,但过
滤并不是其中的一种。
回到 apihelper.py 中的这一行:
methodList = [method for method in dir(object) if callable(getattr(object, method))]
这行看上去挺复杂――确实也很复杂――但是基本结构都还是一样的。整个
过滤表达式返回一个列表,并赋值给 methodList 变量。表达式的前半部分是列
表映射部分。映射表达式是一个和遍历元素相同的表达式,因此它返回每个
元素的值。dir(object) 返回 object 对象的属性和方法列表――你正在映射的列表。
所以唯一新出现的部分就是在 if 后面的过滤表达式。
过滤表达式看上去很恐怖,其实不是。你已经知道了 callable、getattr 和 in。正
如你在前面的部分中看到的,如果 object 是一个模块,并且 method 是上述模
块中某个函数的名称,那么表达式 getattr(object, method) 将返回一个函数对象。
所以这个表达式接收一个名为 object 的对象,然后得到它的属性、方法、函数
和其他成员的名称列表,接着过滤掉我们不关心的成员。执行过滤行为是通
过对每个属性/方法/函数的名称调用 getattr 函数取得实际成员的引用,然后
检查这些成员对象是否是可调用的,当然这些可调用的成员对象可能是方法
或者函数,同时也可能是内置的 (比如列表的 pop 方法) 或者用户自定义的 (比
如 odbchelper 模块的 buildConnectionString 函数)。这里你不用关心其它的属性。
Example 4.17. and-or 技巧介绍
>>> a = "first"
>>> b = "second"
>>> 1 and a or b (1)
'first'
>>> 0 and a or b (2)
'second'
(1) 这个语法看起来类似于 C 语言中的 bool ? a : b 表达式。整个表达式从左到
右进行演算,所以先进行 and 表达式的演算。1 and 'first' 演算值为 'first',
然后 'first' or 'second' 的演算值为 'first'。
(2) 0 and 'first' 演算值为 False,然后 0 or 'second' 演算值为 'second'。
Example 4.19. 安全使用 and-or 技巧
>>> a = ""
>>> b = "second"
>>> (1 and [a] or [b] )[0] (1)
''
(1) 由于 [a] 是一个非空列表,所以它决不会为假。即使 a 是 0 或者 '' 或者其它假值,列表 [a] 也为真,因为它有一个元素。
到现在为止,这个技巧可能看上去问题超过了它的价值。毕竟,使用 if 语句
可以完成相同的事情,那为什么要经历这些麻烦事呢?哦,在很多情况下,
你要在两个常量值中进行选择,由于你知道 a 的值总是为真,所以你可以使
用这种较为简单的语法而且不用担心。对于使用更为复杂的安全形式,依然
有很好的理由要求这样做。例如,在 Python 语言的某些情况下 if 语句是不允许使用的,比如在 lambda 函数中。
Example 4.20. lam bda 函数介绍
>>> def f(x):
... return x*2
...
>>> f(3)
6
>>> g = lambda x: x*2 (1)
>>> g(3)
6
>>> (lambda x: x*2)(3) (2)
6
(1) 这是一个 lambda 函数,完成同上面普通函数相同的事情。注意这里的简短的语法:在参数列表周围没有括号,而且忽略了 return 关键字 (隐含存在,因为整个函数只有一行)。而且,该函数没有函数名称,但是可以将它赋值给一个变量进行调用。
(2) 使用 lambda 函数时甚至不需要将它赋值给一个变量。这可能不是世上最有用的东西,它只是展示了 lambda 函数只是一个内联函数。总的来说,lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个达式的值。lambda 函数不能包含命令,包含的表达式不能超过一个。不要试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。
4.7.1. 真实世界中的 lambda 函数
apihelper.py 中的 lambda 函数:
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
注意这里使用了 and-or 技巧的简单形式,它是没问题的,因为 lambda 函数在
布尔环境中总是为真。(这并不意味这 lambda 函数不能返回假值。这个函数对
象的布尔值为真;它的返回值可以是任何东西。)
还要注意的是使用了没有参数的 split 函数。你已经看到过它带一个或者两个
参数的使用,但是不带参数它按空白进行分割。
Example 4.21. spl it 不带参数
>>> s = "this is\na\ttest" (1)
>>> print s
this is
a test
>>> print s.split() (2)
['this', 'is', 'a', 'test']
>>> print " ".join(s.split()) (3)
'this is a test'
(1) 这是一个多行字符串,通过使用转义字符的定义代替了三重引号。\n 是一个回车,\t 是一个制表符。
(2) 不带参数的 split 按照空白进行分割。所以三个空格、一个回车和一个制表符都是一样的。
(3) 通过 split 分割字符串你可以将空格统一化;然后再以单个空格作为分隔符用 join 将其重新连接起来。这也就是 info 函数将多行 doc string 合并成单行所做的事情。
那么 info 函数到底用这些 lambda 函数、split 函数和 and-or 技巧做了些什么呢?
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
Example 3.24. List 解析介绍
>>> li = [1, 9, 8, 4]
>>> [elem*2 for elem in li] (1)
[2, 18, 16, 8]
>>> li (2)
[1, 9, 8, 4]
>>> li = [elem*2 for elem in li] (3)
>>> li
[2, 18, 16, 8]
Example 3.25. key s, values 和 i tems 函数
>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.keys() (1)
['server', 'uid', 'database', 'pwd']
>>> params.values() (2)
['mpilgrim', 'sa', 'master', 'secret']
>>> params.items() (3)
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
Example 3.26. buildConn ect io nStr ing 中的 l ist 解析
>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.items()
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
>>> [k for k, v in params.items()] (1)
['server', 'uid', 'database', 'pwd']
>>> [v for k, v in params. items()] (2)
['mpilgrim', 'sa', 'master', 'secret']
>>> ["%s=%s" % (k, v) for k, v in params.items()] (3)
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
Example 3.28. 分割字符串
>>> li = ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
>>> s = ";".join(li)
>>> s
'server=mpilgrim;uid=sa;database=master;pwd=secret'
>>> s.split(";") (1)
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
>>> s.split(";", 1) (2)
['server=mpilgrim', 'uid=sa;database=master;pwd=secret']
(1) split 与 join 正好相反,它将一个字符串分割成多元素 list。注意,分隔符 (“;
”) 被完全去掉了,它没有在返回的 list 中的任意元素中出现。
(2) split 接受一个可选的第二个参数,它是要分割的次数。(“哦,可选参数…
…”,您将会在下一章中学会如何在您自己的函数中使用它。)
Ti p: 用 spli t 搜索
anystring.split(delimiter, 1) 是一个有用的技术,在您想要搜索一个子串,然后分别
处理字符前半部分 (即 list 中第一个元素) 和后半部分 (即 list 中第二个元素)
时,使用这个技术。
变量
连续值赋值:(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
字符串的格式化
>>> k = "uid"
>>> v = "sa"
>>> "%s=%s" % (k, v)
'uid=sa'
注意 (k, v) 是一个 tuple。我说过它们对某些东西有用。
您可能一直在想,做了这么多工作只不过是为了做简单的字符串连接。您想
的不错,只不过字符串格式化不只是连接。它甚至不仅仅是格式化。它也是
强制类型转换
Example 3.22. 字符串格式化与字符串连接的比较
>>> uid = "sa"
>>> pwd = "secret"
>>> print pwd + " is not a good password for " + uid (1)
secret is not a good password for sa
>>> print "%s is not a good password for %s" % (pwd, uid) (2)
secret is not a good password for sa
>>> userCount = 6
>>> print "Users connected: %d" % (userCount, ) (3) (4)
Users connected: 6
>>> print "Users connected: " + userCount (5)
Traceback (innermost last):
File "<interactive input>", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects
(1) + 是字符串连接操作符。
(2) 在这个简单例子中,字符串格式化实现与连接一样的结果。
(3) (userCount, ) 是一个只包含一个元素的 tuple。是的,语法有一点奇怪,但是
使用它的理由就是:显示地指出它是一个 tuple,而不是其他。实际上,
当定义一个 list、tuple 或 dictionary 时,您可以总是在最后一个元素后面
跟上一个逗号,但是当定义一个只包含一个元素的 tuple 时逗号是必须的。
如果省略逗号,Python 不会知道 (userCount) 究竟是一个只包含一个元素的
tuple 还是变量 userCount 的值。
(4) 字符串格式化通过将 %s 替换成 %d 即可处理整数。
(5) 试图将一个字符串同一个非字符串连接会引发一个异常。与字符串格式化
不同,字符串连接只能在被连接的每一个都是字符串时起作用。
有关 dictionary、tuple、和 list
- Tuple 是不可变的 list。一旦创建了一个 tuple,就不能以任何方式改变它。如t = ("a", "b", "mpilgrim", "z", "example")
- List 是 Python 中使用最频繁的数据类型。如: li =["a", "b", "mpilgrim", "z", "example"]
- Dictionary 是 Python 的内置数据类型之一,它定义了键和值之间一对一的关系。如:
d = {"server":"mpilgrim", "database":"master"}
Tuple 可以转换成 list,反之亦然。内置的 tuple 函数接收一个 list,并返回一个有着相同元素的 tuple。而 list 函数接收一个 tuple 返回一个 list。从效果上看,tuple 冻结一个 list,而 list 解冻一个 tuple。
2008年5月1日
--oracle的日志和控制文件恢复
昨天下午一直到今天下午,一整天的时间经历了一场Windows优化大师的带来的“恶梦”,本不该怪罪这位“大师”的,原因在于自己用了这位“大师”,希望使用oracle的朋友在使用它时要注意一些问题。不然让它删除log和dmp文件。有可能大家都知道了,不过我还是第一次遇到,下面把这期间发生的事情讲给大家听:
昨天下午觉得系统比较慢,想起了Windows优化大师,于是乎下了个最新版安装、运行、“优化”,果然系统里删除了好多“垃圾”(在不知情之下,这些所谓的垃圾包括有用的注册表、珍贵的Oracle备份文件.dmp)。
“优化”之后,我的Oracle起不来了。怎么办?于是:
1)遂google了一下,发现优化大师会优化imagePath注册表,于是到注册表里去改。改完后重启,Oracle 仍然不能连接,没办法
2)系统还原吧,还原后仍然不能用,难道不是注册表的问题?没办法
3)新建了一个实例,准备找来刚刚备的Dmp文件恢复。晕!.dmp文件哪里去了?难道隐藏了?解开隐藏属性。汗!仍然没有?
我一拍脑袋,想起了“优化”大师干掉的吧,系统又还原了,怎么办?电脑里上百个.dmp文件都没了,十几年的备份。由于前天备份的硬盘坏了,格式化后还没有来得及把.dmp文件备到新硬盘里去。也就是说“大师”可能杀了我们十几年的资料。于是:
1)要么恢复.dmp文件
2)要么修复oracle。但是:
找来easy-recover和R-studio两个硬盘恢复软件,把.dmp文件恢复出来,但是导入数据时总是出现"未知的字符集",google后发现并非字符集出问题,而是文件恢复有问题,打电话给硬盘恢复公司,说要重组dmp文件,需要十几万或几万。只有选择第2)套方案修复oracle了。我对oracle也是一知半解,没有做过恢复工作,所以绕了好多弯。
先看alter.log日志文件吧,发现找不到重做日志文件red01.log和red02.log。再次崩溃!“优化”大师把我的log日志文件也给删除了!怎么办?QQ群里的朋友提示:重建日志文件了,网上找来了很多办法,做了一晚,怎么也不成功,毕竟我是二把刀!在痛不欲生的情况下,第二天一大早,找到了一位oracle数据库管理员,请教了一番,他告诉我只要表空间文件还在控制文件和日志文件坏了都是可以恢复的,终于在他的指导下我完成了数据库修复工作,下面这个方面比网上一些方法要简单一些,我把它记下来供自己查阅也供遇到此类事件的朋友使用。
背景描述:oracle实例A的日志文件被误删除,同时因为后期修复过程中的误操作把控制文件也给破坏了。解决思路是:新建一个干净的实例,把坏掉实例的表空间数据文件倒进干净的实例中,并重新建立日志与控制文件的关联。具体做法如下:
1)新建一个实例B(D:\ORACLE\ORADATA\B\),到“服务”里停止实例B;
2)把实例A所有的.dbf文件拷贝到实例A里
3)“服务”启动实例B;
4)进入DOS,
c:/>sqlplus /nolog
sql>connect /@instancename as sysdba;
sql>startup ummount;
--下面是关键的一步,建立控制文件的关联
sql>CREATE CONTROLFILE REUSE DATABASE "B" RESETLOGS NOARCHIVELOG
-- SET STANDBY TO MAXIMIZE PERFORMANCE
MAXLOGFILES 50
MAXLOGMEMBERS 5
MAXDATAFILES 100
MAXINSTANCES 1
MAXLOGHISTORY 226
LOGFILE
GROUP 1 'D:\ORACLE\ORADATA\B\REDO01.LOG' SIZE 100M,
GROUP 2 'D:\ORACLE\ORADATA\B\REDO02.LOG' SIZE 100M,
GROUP 3 'D:\ORACLE\ORADATA\B\REDO03.LOG' SIZE 100M
-- STANDBY LOGFILE
DATAFILE
'D:\ORACLE\ORADATA\B\SYSTEM01.DBF',
'D:\ORACLE\ORADATA\B\UNDOTBS01.DBF',
'D:\ORACLE\ORADATA\B\CWMLITE01.DBF',
'D:\ORACLE\ORADATA\B\DRSYS01.DBF',
'D:\ORACLE\ORADATA\B\EXAMPLE01.DBF',
'D:\ORACLE\ORADATA\B\INDX01.DBF',
'D:\ORACLE\ORADATA\B\ODM01.DBF',
'D:\ORACLE\ORADATA\B\TOOLS01.DBF',
'D:\ORACLE\ORADATA\B\USERS01.DBF',
'D:\ORACLE\ORADATA\B\XDB01.DBF';
--关于DATAFILE里的内容,需要大家自己根据情况修改。
sql>shutdown
sql>startup mount
sq;>alter database open resetlogs;
5)这样应该就可以了,如果不行,关闭,重新连接应该就可以了。
经历这次事件,体会以下几点:
1)做开发和数据库管理的人不可以随便去使用一些软件,使用时更要仔细检查它的功能,阅读文档。
2)以前学的oracle知识大多一知半解,也很少去应用,这次的折腾以成功结束,所以对oracle有了更多的体会,也更喜欢这个数据库。
3)备份工作一定要持之以恒,不能只备在硬盘和活动硬盘里,还要备在光驱里,建立归档制度。
4)遇到困难时,热心的朋友真是多啊。网上的朋友和朋友介绍的朋友都很热心,对我的无知给给予了很多理解、同情和帮助。
2007年4月6日
近日收到导师关于论文答辩的Email,由于在职学习,时间总是不够用,加上懈怠,论文工作期限已近一年了。然而论文的进展才到一小半而己,只有利用夜里开工加班了。目前的论文是一套B/S系统,基于.net的评审系统的研究与开发。前两天,与Tony Qu在msn上chat时,受到启发,需要更多地将设计模式应用的内容扩展到论文中,既然是采用asp.net2.0,那么Provider模式自是重点。Tony给了我一大堆好文链接,正在加油学习,另外,微软asp.net官方网站推荐的startkit中,有一个项目叫做TheBeerHouse对Provider有很好的讲解,而且是一套较为完整的asp.net学习案例,现在已经读到Charpter5了,再有一个星期叫差不多学习完。准备近期能逐步将一些模式、结合TheBeerHouse、Petshop以及我现在的论文,写一些文章。
2007年4月5日
阅读之所以开心,是因为没有时间去计较平日里的不快和细节,享受作者思想的洗礼,眼前变得开阔,平静且激动。年初读的几本书总让我自我陶醉,信心百倍地面对人生,比如托夫勒的《第三次浪潮》、德鲁克的《卓有成效的管理者》。这些书读罢时隔也有一两个月了,读的时候心情总是激动,我在我的人生中追逐着我的真理,然而价值观总是不停摇摆,总想保留“属于自己的”一些不变的想法经常会受到大众的价值的影响,使我迷惑于这个世界。然而在阅读这些大师的作品时,总能找到放大“属于自己的”那一部分信念,这让我激动,使我找到了更多的理论支持,坚持自己现在走的路,并且找到校正自己的坐标。
2006年12月3日
如果您还没有阅读本系列开篇《CardViewer项目体会系列文章》,建议花些时间了解一下。
为什么重要:如果软件难于使用,如果它迫使你犯错误,如果它阻止你通过努力达到目标,你将不会喜欢它,不管它展示了什么计算机能力和提供了什么功能。因为界面影响用户对软件的感觉,因此,它必须是正确的。--Entry from 《Software Engineering--A practitioner's Approach》
废话:前一篇 CardViewer系列之杂篇--成功是个贫乏的教师 谈到,经与用户的一次失败交互找到了主要原因是在UI方面,所以一直希望从理论角度来解释实践以及提升实践能力,毕竟,理论是实践之后的产物,所以对于后人来讲,实践之后获得的理论才是有生命力以及生命的延续力(还原以及创造)。近几日重温了《Software Engineering--A practitioner's Approach》的有关章节,并阅读了教材中推荐的一些读物,如Theo Mandel的著作的第五章《The Golden Rules of User Interface Design》,有了一点体会和的认知。
UI设计的概念:用户界面设计在人和计算机间创建一个有效的通信媒介。遵循一组界面设计原则,设计任务需标识界面对象和动作,然后创建屏幕布局,形成用户界面原型的基础。
界面设计不只是美工:初次接触的UI design这个词汇时,对它的理解是如何把用户交互的界面(图形)设计的漂亮,对,界面设计基本上等同于美工,如同网站建设中的CSS和Skin。天啊,是这个名字给我的误解,我不是也不善美工,所以这不是我关心的内容,把它交给专业的美工吧。如果我们了解一下设计模型和用户设计过程是怎么一回事,就应该改变这种观点。
设计模型的种类:分四种。软件工程师创建设计模型;人员工程师(或者也是软件工程师)建立用户模型;终端用户在脑海里对产生的映名称为用户的模型或系统感觉;系统的实现者创建系统映像。前篇中涉及的问题,主要体现在用户模型与用户的系统感觉发生的冲突,这必然导致的冲突和交互失败。因为四种模不可避免地会有差距,我们要做的是减小差距。初期建立的用户模型更多地顾及到软件的设计而非用户,实际上,用户的背景性别年龄以及使用掌上电脑的熟练程度是把握调适模型平衡的关键因素,对用户以及任务的把握显得至关重要。
用户设计过程:用户、任务和环境分析及建模;界面设计;界面构造;界面确认。不难看出,界面设计的工作似乎伴随到软件需求分析和设计甚至更多过程的整个周期,如果界面设计时不能正确把握任务和用户以及环境,那么设计将会不断修改甚至推翻。如掌上电脑不同于PC,甚至与smartPhone的特征也不尽相同,手写输入法的使用以及用户偏好使用,不同PPC的屏幕大小的细微差别,是使用多个窗体还是使用一个窗体多个面板或他控件,不同年龄人群适合不同的字体大小,交互方式的难易程度,提供多种选择模式以适合不同用户分类(新手、对系统有了解的中级用户,对系统有了解的经常用户)。
美工只是界面设计的一个重要的部分,更多的是用来提升亲和力和感染力、舒适度。而非UI的大部分。
界面设计文章推荐:我想如果你有空拜读一下Theo Mandel的著作并开发或参与过任何一个完整的项目(不管项目的大小,只要完整),一定会受益良多。其中最为著名的就是以下三条黄金规则(原著中对这三条原则进行的丰富的解释,这里列出条目,详细内容不再copy,有兴趣的话点这里下载PDF):
- Place Users in Control
- Reduce Users' Memory Load
- Make the Interface Consistent
说明:未标示Entry from 的灰色字体表示摘录的原文及翻译内容,原文及链接已经给出。
近几天一直在学习Terrylee/的有关模式的系列文章,受益不小,另外, 也跟我谈到过Mobile Client Software Factory的内容,感觉很值得研究,所以希望与大家一起研究并交流。
一部不是很热的老美剧《实习医生格蕾》让我回想起六年前做实习医生的幕幕往事。格蕾进入实习医院的第一幕是手术台和竞争伙伴,他们渴望获得展示的机会但又遇到重重挫折,他们渴望给病人已最大的安慰却不得不面对手术失败受到的谴责,他们象青苹果一样稚难却又精神饱满,他们时而徘徊自己的选择却又互相共勉当初的信仰。
六年前我也是一名实习医生,我渴望以最快的速度站在手术台优雅地操作手术刀,我满心幸福地听到建立起友谊的病人尊敬地叫我医生,我曾面临第一次单独处理急症时的恐惧,也曾经为处理完一件小小的医疗事件而兴奋地一夜不眠。竞争伙伴即是对手也是共勉的朋友,压力、快乐、安慰、一起有过痛苦的选择、一起感受成功的幸福,有时你不得己你要击败朋友并承受朋友变成我的假想敌,但是最终我们还是真诚地拥抱。我们一起用我们的所做追求着技能,思索着职业的哲理,思索着病人与医生,病人与病人,医生与医生......
如今已经不再是一名医生,但是我感激着那时的一切和一切......
2006年11月29日
摘要: 本文尚属片断式的个人想法,或文过饰非,或自作多情,不敢苟求认同。旨在:希望博客园“资本”积累之初,不忘内功修炼,形成“园子文化”,方属长久之道。谨代表“我想出一份力”。引言:我喜欢的词汇。相比“加入”,更喜欢“参与”,我“参与”博客园社区,这样的话,我将参...
阅读全文