Python 众多强大功能之一:自省
Python 中万物皆对象
自省是指代码可以查看内存中以对象形式存在的其它模块和函数,获取它们的信息,并对它们进行操作。
使用可 选参数 和命名 参数
Python 允许函数参数有缺省值;如果调用函数时不使用参数,参数将获得它的缺省值。此外,通过使用命名参数还可以以任意顺序指定参数。
info函数
def info(object, spacing=10, collapse=1):
info 的有效调用
info(odbchelper)
info(odbchelper, 12)
info(odbchelper, collapse=0)
info(spacing=15, object=odbchelper)
甚至必备参数 (例如 object,没有指定缺省值) 也可以采用命名参数的方式,而且命名参数可以以任意顺序出现。
Note: 灵活的函数调用
调用函数时唯一必须做的事情就是为每一个必备参数指定值 (以某种方式);以何种具体的方式和顺序都取决于你。
使用 type、str、dir 和其它内置函数
type 函数
dir 介绍
>>> li = []
>>> dir(li) (1)
['append', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']
>>> d = {}
>>> dir(d) (2)
['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values'] >>> import odbchelper
>>> dir(odbchelper) (3)
['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']
-
(1) li 是一个列表,所以 dir(li) 返回一个包含所有列表方法的列表。注意返回的列表只包含了字符串形式的方法名称,而不是方法对象本身。
-
(2) d 是一个字典,所以 dir(d) 返回字典方法的名称列表。其中至少有一个方法,keys,看起来还是挺熟悉的。
-
(3) 这里就是真正变得有趣的地方。odbchelper 是一个模块,所以 dir(odbchelper)返回模块中定义的所有部件的列表,包括内置的属性,例如__name__、__doc__,以及其它你所定义的属性和方法。在这个例子中,odbchelper 只有一个用户定义的方法
最后是 callable 函数,它接收任何对象作为参数,如果参数对象是可调用的,返回 True;否则返回 False。
内置函 数
type、str、dir 和其它的 Python 内置函数都归组到了 __builtin__ (前后分别是双下划线) 这个特殊的模块中。如果有帮助的话,你可以认为 Python 在启动时自动执行了 from __builtin__ import *,此语句将所有的 “内置” 函数导入该命名空间,所以在这个命名空间中可以直接使用这些内置函数。
通过 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'
-
(1) 该语句获取列表的 pop 方法的引用。注意该语句并不是调用 pop 方法;调用 pop 方法的应该是 li.pop()。这里指的是方法对象本身。
-
(2) 该语句也是返回 pop 方法的引用,但是此时,方法名称是作为一个字符串参数传递给 getattr 函数的。getattr 是一个有用到令人无法致信的内置函数,可以返回任何对象的任何属性。在这个例子中,对象是一个 list,属性是pop 方法。
-
(3) 如果不确信它是多么的有用,试试这个:getattr 的返回值是 方法,然后你就可以调用它,就像直接使用 li.append("Moe")一样。但是实际上你没有直接调用函数;只是以字符串形式指定了函数名称。
-
(4) getattr 也可以作用于字典。
-
(5) 理论上,getattr 可以作用于元组,但是由于元组没有方法,所以不管你指
定什么属性名称 getattr 都会引发一个异常。
用于模块的 getattr
getattr 不仅仅适用于内置数据类型,也可作用于模块
getatt r 作为一 个分发者
getattr 常见的使用模式是作为一个分发者
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 模块中相应函数的引用。
你是否发现前面示例的一个 Bug?即字符串和函数之间的松耦合,而且没有错误检查。如果用户传入一个格式参数,但是在 statsout中没有定义相应的格式输出函数,会发生什么呢?还好,getattr 会返回 None,它会取代一个有效函数并被赋值给 output_function,然后下一行调用函数的语句将会失败并抛出一个 异常。这种方式不好。值得庆幸的是,getattr 能够使用可选的第三个参数,一个缺省返回值。
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 是相当强大的。它是自省的核心,在后面的章节中你将看到它更强大的示例。
过滤列 表
methodList = [method for method in dir(object) if callable(getattr(object, method))]
and 和 or 的特殊性质
and 介绍
>>> 'a' and 'b' (1) 'b' >>> '' and 'b' (2) '' >>> 'a' and 'b' and 'c' (3) 'c'
(2) 如果布尔环境中的某个值为假,则 and 返回第一个假值。在这个例子中,'' 是第一个假值。
(3) 所有值都为真,所以 and 返回最后一个真值,'c'。
or 介绍
>>> 'a' or 'b' (1) 'a' >>> '' or 'b' (2) 'b' >>> '' or [] or {} (3) {} >>> def sidefx(): ... print "in sidefx()" ... return 1 >>> 'a' or sidefx() (4) 'a'
(1) 使用 or 时,在布尔环境中从左到右演算值,就像 and 一样。如果有一个值为真,or 立刻返回该值。本例中,'a' 是第一个真值。
(2) or 演算 '' 的值为假,然后演算 'b' 的值为真,于是返回 'b' 。
(3) 如果所有的值都为假,or 返回最后一个假值。or 演算 '' 的值为假,然后演算 [] 的值为假,依次演算 {} 的值为假,最终返回 {} 。
bool and A or B
if bool = 1
return B
else
return A
-