Python学习笔记 === python自省
- 示例代码:
from types import BuiltinFunctionType, BuiltinMethodType, \ FunctionType, MethodType, ClassType def help(object, spacing=10, collapse=1): """Print method and doc string. Takes module, class, list, dictionary, or string.""" typeList = (BuiltinFunctionType, BuiltinMethodType, FunctionType. MethodType, ClassType) methodList = [method for method in dir(object) if type(getattr(object, method)) in typeList] processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s:s) print "\n".join(["%s %s" % (method.ljust(spacing), processFunc(str(getattr(object, method).__doc__))) for method i n methodList]) if __name__ == "__main__": print help.__doc__
- 自省综述:根据上边示例代码分析
- 这个模块有一个函数,help, 有三个参数object, spacing, collapse, 后两个是可选参数
- 函数的代码是缩排的,help函数有一个多行的文档字符串,并没有返回值,因为函数只使用他的效果并非它的值
- __name__技巧只是用于测试模块,在别的程序引入这个模块的时候不会引起冲突,
- help函数的设计是为了在ide环境下是用的,接受任何拥有函数或者方法的对象,打印出对象所有的函数和文档字符串
- 用法举例
>>> from apihelper import help >>> li = [] >>> help(li) append L.append(object) -- append object to end count L.count(value) -> integer -- return number of occurrences of value extend L.extend(list) -- extend list by appending list elements index L.index(value) -> integer -- return index of first occurrence of value insert L.insert(index, object) -- insert object before index pop L.pop([index]) -> item -- remove and return item at index (default last) remove L.remove(value) -- remove first occurrence of value reverse L.reverse() -- reverse *IN PLACE* sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
- 高级用法:注意参数变化
>>> import odbchelper >>> help(odbchelper) buildConnectionString Build a connection string from a dictionary Returns string. >>> help(odbchelper, 30) buildConnectionString Build a connection string from a dictionary Returns string. >>> help(odbchelper, 30, 0) buildConnectionString Build a connection string from a dictionary Returns string.
- 导入模块:两种导入模块的方法
- 基本的from module import 语法
from types import BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, ClassType
注意:与module导入方法类似,但是,导入模块types的属性和方法被直接导入到局部名字空间中,使用的时候不用模块的名字来限定;
- import 和 from module import 对比
>>> import types #只是有每个对象类型的属性 >>> types.FunctionType #必须用module 名称来限定 <type 'function'> >>> FunctionType #没有定义在当前的名字空间中,只是存在与types的上下问环境当中 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'FunctionType' is not defined >>> from types import FunctionType >>> FunctionType <type 'function'>
- 什么时候要用from module import
- 如果想经常存取模块的属性和方法,但是不想一遍遍的敲入模块名称
- 想选择性的导入某些属性和方法,不想要其他的
- 如果模块包含的属性或者方法和你自己的某个模块名字相同,只能用import module
- 基本的from module import 语法
- 可选和定名参数(指定参数名字):
- help的合法调用
help(odbchelper) help(odbchelper, 12) help(odbchelper, collapse=0) #spacing 缺省 help(spacing=15, object=odbchelper) #object可以定名,任意顺序都行
- help的合法调用
- type,str,dir和其他内置函数:
- type:返回任意对象的数据类型
>>> type("333") <type 'str'> >>> li=[] >>> type(li) <type 'list'> >>> import odbchelper >>> type(odbchelper) <type 'module'> >>> import types >>> type(odbchelper) == types.ModuleType True
- str:强制将数据转换为字符串
>>> str(1) '1' >>> ho = ["sd", 1, "sdd"] #可以工作于任何类型的任何对象 >>> str(ho) "['sd', 1, 'sdd']" >>> str(odbchelper) #模块的字符串表示包含了模块在磁盘上的路径 "<module 'odbchelper' from 'odbchelper.pyc'>" >>> str(None) #python空值 返回字符串 很重要??? 'None'
- dir:help函数的核心,返回任意一个对象的属性和方法的列表:模块,函数,字符串,列表,字典... 相当多的东西
>>> li = [] >>> dir(li) ['append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] >>> d = {} >>> dir(d) ['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values'] >>> import odbchelper >>> dir(odbchelper) #模块,返回模块中定义的所有东西,包括自定义的 ['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']
- 内置属性和函数
>>> from apihelper import help >>> help(__builtins__, 20) ArithmeticError Base class for arithmetic errors. AssertionError Assertion failed. AttributeError Attribute not found. EOFError Read beyond end of file. EnvironmentError Base class for I/O related errors. Exception Common base class for all exceptions. FloatingPointError Floating point operation failed. IOError I/O operation failed. [...snip...] ???
- 综合:type dir str, 以及所有其他的python内置函数一样被组合进入一个名字叫做__builtins__的特别模块中,python启动的时候自动from __builtins__ import * 可以直接使用,好处是,可以通过得到builtins的信息,作为一个组,存取所有内置的函数和属性,help函数实现了那个功能。???
- type:返回任意对象的数据类型
- 使用getattr得到对象的各种引用:可以得到一个直到运行时候才知道的函数的引用???
- getattr介绍
>>> li=["larry", "curly"] >>> li.pop #得到列表的pop方法的一个引用,并不是调用pop方法,而是方法本身 <built-in method pop of list object at 0xb7724f4c> >>> getattr(li, "pop") #也返回pop方法的一个引用,但是,方法的名字被指定为一个字符串参数,getattr可以返回任意对象的任意属性,在这个例子中,对象是列表,属性是pop方法 <built-in method pop of list object at 0xb7724f4c> >>> getattr(li, "append")("moe") #li.append("moe") 返回值是方法,没有直接调用方法,而是把函数名当作字符串来指定。 >>> li ['larry', 'curly', 'moe'] >>> getattr({}, "clear") #也可以用给字典 <built-in method clear of dict object at 0x828e604> >>> getattr((), "pop") #理论上可以用个序列,但是序列没有方法,所以不管给出什么属性名,getattr都将引发一个异常, Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'tuple' object has no attribute 'pop'
- 用于apihelper.py, 不仅可以用于内置数据类型,也可以用于模块
>>> import odbchelper >>> odbchelper.buildConnectionString #返回在odbchelper模块中的bulidConnectionString函数的引用 <function buildConnectionString at 0x820bb8c> >>> getattr(odbchelper, "buildConnectionString") #使用getattr,我们可以得到同一函数的同一引用。 相当于object.attribute. 如果object是一个模块,那么attribute可以是模块中的任何东西:函数,类,或者全局变量。 <function buildConnectionString at 0x820bb8c> >>> object = odbchelper >>> method = "buildConnectionString" >>> getattr(object, method) #help函数中用到的东西,method字符串是方法或者函数的名字。 <function buildConnectionString at 0x820bb8c> >>> type(getattr(object, method)) 本地方method是一个函数的名字 <type 'function'> >>> import types >>> type(getattr(object, method)) == types.FunctionType True
- getattr介绍
- 过滤列表:python强大的列表映射到其他列表的能力,同一种过滤机制合并,列表中的某个元素被映射,其他的都忽略掉。
- 列表过滤语法
[mapping-expression for element in source-list if filter-expression]
以if开头的就是过滤表达式,可以是任意真假的表达式,任何对于过滤表达式计算出真值的元素将包括在映射中,其他元素忽略掉,他们不会出现在映射表达式中,也不包括在输出列表中。
- 列表过滤介绍
>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"] >>> [elem for elem in li if len(elem) > 1] ['mpilgrim', 'foo'] >>> [elem for elem in li if elem != "b"] # 过滤掉特殊值b,每次b出来过滤表达式都不成立 ['a', 'mpilgrim', 'foo', 'c', 'd', 'd'] >>> [elem for elem in li if li.count(elem) == 1] #count返回的是一个元素出现的次数 ['a', 'mpilgrim', 'foo', 'c']
- apihelper.py中过滤列表
typeList = (BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, ClassType) methodList = [method for method in dir(object) if type(getattr(objec, method)) in typeList]
看上去挺复杂,但是基本结构是一样的。整个表达式返回一个列表,列表赋给变量methodList,前半部分是列表映射部分,dir(object)返回一个对象的属性和方法的列表,就是正在映射的列表。表达式getattr(object, method)返回一个函数对象,method是模块中的函数名字,这个表达式接受一个object对象,获得它的属性方法,和一些其他东西的名字列表,然后过滤列表,执行过滤通过得到每个属性方法函数的名字,让后通过getattr函数得到指向实际东西的引用。然后用type检查对象类型,我们关心方法和函数,不关心其他属性。classType对象现在不用担心,后边将讨论python的类。
- 列表过滤语法
- and-or技巧:要对比bool?a:b 理解其如何工作
>>> a = "first" >>> b = "second" >>> 1 and a or b #类似c 'first' >>> 0 and a or b #类似c 'second' >>> a = "" >>> 1 and a or b #区别,看成纯粹的布尔逻辑去分析。 'second' >>> a = "" >>> b = "second" >>> 1 and a or b 'second' >>> 0 and a or b 'second' >>> (1 and [a] or [b])[0] [a] 是一个非空列表 永远为真, ''
Python 中很多时候,不允许使用if语句,一个负责的的程序猿应该将and or 技巧封装成函数:
def choose(bool, a, b): return (bool and [a] or [b])[0]
???
- 使用lambda函数:快速定义单行的最小函数,可以被用在任何需要函数的地方,函数的语法通常与其他函数有点不同???
- lambda函数介绍
>>> def f(x): ... return x*2 ... >>> f(2) 4 >>> g = lambda x: x*2 #lambda函数, 没有小括号,return是默认的,函数没有名字。只有将它赋值给变量的变量名g >>> g(3) 6 >>> (lambda x: x*2)(3) #可以不赋值给一个变量然后使用它,证明是一个内联函数 6
可以接收任意多个参数(包括可选参数)值并且返回单个表达式的值的函数,lambda函数不能包括命令,表达式不能超过一个,不要赛入过多东西。
lambda函数是风格问题,不一定非要使用,许多小的一行代码不会弄乱我的代码,用在需要特殊封装的,非重用的代码上。
- 例子中的lambda函数
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
lambda函数在一个布尔环境下总为真,并不意味着不能返回假值,函数本身总是真,返回值可以任何值。
- split不带参数:上边式子中不带参数
>>> s = "this is\na\ttest" >>> print s this is a test >>> print s.split() # split不带参数按空白进行分割!!! ['this', 'is', 'a', 'test'] >>> print " ".join(s.split()) #将空白统一化!!! 'this is a test'
- 将函数赋给一个变量
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
processFunc现在是一个函数,但是函数为哪一个要看collapse的值。如果为真processFunc(string)将压缩空白,否则,将返回未改变的参数。
- 注意:其他不健壮的语言实现它,可能创建一个函数,它接收一个字符串和一个collapse函数,使用一个If语句来判断是否需要压缩空白或者不压缩,然后返回相应的值,但是这样效率比较低,每次调用它,不得不再给出想要的东西之前,判断是否空白。在python中,可以将这种判断逻辑拿到函数之外,定义一个裁剪过的函数lambda来给出确切的(唯一的)你想要的。这样做更有效率更漂亮,并且更少导致那些令人讨厌的错误???
- lambda函数介绍
- 全部放在一起:所有的多米诺骨牌拼接到一起了,然后将它推倒吧。
-
- 最后一行的内容
print "\n".join(["%s %s" % (method.ljust(spacing), processFunc(str(getattr(object, method).__doc__))) for method in methodList])
-
- 最后一句告诉我们这是一个列表映射,methodLIst是一个在object中所有我们关心的方法的列表。我们用method遍历列表
- 动态得到文档字符串
>>> import odbchelper >>> object = odbchelper #object是我们要得到的帮助的对象 >>> method = 'buildConnectionString' #method 是当前方法的名字 >>> getattr(object, method) #得到在object模块中对于method函数的一个引用 <function buildConnectionString at 010D6D74> >>> print getattr(object, method).__doc__ #打印文档字符串 Build a connection string from a dictionary of parameters. Returns string. #至于str 是一个 内置函数,强制转换数据,但是不是每个函数都有文档字符串,如果没有的话,__doc__属性是None.
- 为什么对一个文档字符串使用str
>>>{}.keys__doc__ >>>{}.keys__doc__ == None 1 >>>str({}.keys__doc__) #使用str函数就接收了空值,返回它的字符串表示 None
然后保证有了字符串,传递字符串给processFunc,这个函数定义了一个要不要压缩空白或者不压缩,因为process假定一个字符串参数,并且调用了split方法,如果传给的是方法None,而不是字符串,函数就会失败了。
- ljust方法介绍
>>>s = "build" >>>s.ljust(30) #用空格填充到指定长度,这样就可以继续对齐了 "build " >>>s.ljust(2) #少于字符串的话 返回原字符串 "build"
- 打印列表
>>>li=['a','b'] >>>print "\n".join(li) # 一个有用的调试技巧
11,小结
- apihelper.py代码和输出
# 代码 from types import BiultinFunctionType, BulitinMethodType, FunctionType, MethodType, ClassType def help(object, collapse=1, spacing=10): ""Print methods and doc string. Take module, class, list, dictionary, or string.""" typeList = (BiultinFunctionType, BulitinMethodType, FunctionType, MethodType, ClassType) methodList = [method for method in dir(object) if type(getattr(object, emthod)) in typeList] processFunc = collapse and (lambda s: " ".join(split())) or (lambda s: s) print "\n".join(["%s %s" % (method.ljust(spacing), processFunc(str(getattr(object, method).__doc__))) for method in methodList]) if __name__ == "__main__": print help.__doc__ # 输出 >>> from apihelper import help >>> li = [ ] >>>help(li) append L.append(object) -- append object to end count L.count(value) -> integer -- return number of occurrences of value extend L.extend(list) -- extend list by appending list elements index L.index(value) -> integer -- return index of first occurrence of value insert L.insert(index, object) -- insert object before index pop L.pop([index]) -> item -- remove and return item at index (default last) remove L.remove(value) -- remove first occurrence of value reverse L.reverse() -- reverse *IN PLACE* sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
- 自我完成作业
- 选用Import或者from module import导入模块
- 可选和定名参数定义和调用函数
- str强制转换为字符串表达式
- 使用getattr动态函数得到函数和其他的什么引用
- 扩展映射列表进行列表过滤
- and-or的技巧的应用
- 定义lambda函数
- 将函数赋值给变量,然后通过引用变量调用函数。这种思考方式会提高对python的理解力???
可通过本人转载的“Django实战系列”进行django的进一步学习;另外,实战系列的源代码下载地址:在实战系列文章中留言写下邮箱地址,一天内会发送给你全部源代码。