2.1 自省

自省是指代码可以查看内存中以对象形式存在的其它模块和函数,获取它们的信息,并对它们进行操作。用这种方法,你可以定义没有名称的函数,不按函数声明的参数顺序调用函数,甚至引用事先并不知道名称的函数。


def info(object, spacing=10, collapse=1): 1 2 3    #多行 doc string 被合并到单行中,要改变这个选项需要指定 collapse 参数的值为 0。
                                                               #如果函数名称长于10个字符,你可以将 spacing 参数的值指定为更大的值以使输出更容易阅读
    """Print methods and doc strings.
                                                                #即该参数的设置直接影响后续文档说明的输出排列
    Takes module, class, list, dictionary, or string."""
    methodList = [method for method in dir(object) if callable(getattr(object, method))]
    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 in methodList])

if __name__ == "__main__":                4 5
    print info.__doc__
1该模块有一个声明为 info 的函数。根据它的函数声明可知,它有三个参数: objectspacing collapse。实际上后面两个参数都是可选参数,关于这点你很快就会看到。
2info 函数有一个多行的 doc string,简要地描述了函数的功能。注意这里并没有提到返回值;单独使用这个函数只是为了这个函数产生的效果,并不是为了它的返回值。
3函数内的代码是缩进形式的。
4if __name__ 技巧允许这个程序在自己独立运行时做些有用的事情,同时又不妨碍作为其它程序的模块使用。在这个例子中,程序只是简单地打印出 info 函数的 doc string
5if 语句使用 == 进行比较,而且不需要括号。

info 函数的设计意图是提供给工作在 Python IDE 中的开发人员使用,它可以接受任何含有函数或者方法的对象 (比如模块,含有函数,又比如list,含有方法) 作为参数,并打印出对象的所有函数和它们的 doc string

info 函数就是这样一个例子,它有两个可选参数。


def info(object, spacing=10, collapse=1):

spacingcollapse 是可选参数,因为它们已经定义了缺省值。object 是必备参数,因为它没有指定缺省值。如果调用 info 时只指定一个参数,那么 spacing 缺省为 10collapse 缺省为 1。如果调用 info 时指定两个参数,collapse 依然默认为 1

假如你要指定 collapse 的值,但是又想要接受 spacing 的缺省值。在绝大部分语言中,你可能运气就不太好了,因为你需要使用三个参数来调用函数,这势必要重新指定 spacing 的值。但是在 Python 中,参数可以通过名称以任意顺序指定。


举例: 对一个list查找可以进行相关操作的函数

>>> from apihelper import info
>>> li = [ ]
>>> info(li)
__add__    x.__add__(y) <==> x+y
__class__  list() -> new empty list list(iterable) -> new list initialized from iterable's items
__contains__ x.__contains__(y) <==> y in x
__delattr__ x.__delattr__('name') <==> del x.name
__delitem__ x.__delitem__(y) <==> del x[y]
__delslice__ x.__delslice__(i, j) <==> del x[i:j] Use of negative indices is not supported.
__eq__     x.__eq__(y) <==> x==y
__format__ default object formatter
__ge__     x.__ge__(y) <==> x>=y
__getattribute__ x.__getattribute__('name') <==> x.name
__getitem__ x.__getitem__(y) <==> x[y]
__getslice__ x.__getslice__(i, j) <==> x[i:j] Use of negative indices is not supported.
__gt__     x.__gt__(y) <==> x>y
__iadd__   x.__iadd__(y) <==> x+=y
__imul__   x.__imul__(y) <==> x*=y
__init__   x.__init__(...) initializes x; see help(type(x)) for signature
__iter__   x.__iter__() <==> iter(x)
__le__     x.__le__(y) <==> x<=y
__len__    x.__len__() <==> len(x)
__lt__     x.__lt__(y) <==> x<y
__mul__    x.__mul__(n) <==> x*n
__ne__     x.__ne__(y) <==> x!=y
__new__    T.__new__(S, ...) -> a new object with type S, a subtype of T
__reduce__ helper for pickle
__reduce_ex__ helper for pickle
__repr__   x.__repr__() <==> repr(x)
__reversed__ L.__reversed__() -- return a reverse iterator over the list
__rmul__   x.__rmul__(n) <==> n*x
__setattr__ x.__setattr__('name', value) <==> x.name = value
__setitem__ x.__setitem__(i, y) <==> x[i]=y
__setslice__ x.__setslice__(i, j, y) <==> x[i:j]=y Use of negative indices is not supported.
__sizeof__ L.__sizeof__() -- size of L in memory, in bytes
__str__    x.__str__() <==> str(x)
__subclasshook__ Abstract classes can override this to customize issubclass(). This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
append     L.append(object) -- append object to end
count      L.count(value) -> integer -- return number of occurrences of value
extend     L.extend(iterable) -- extend list by appending elements from the iterable
index      L.index(value, [start, [stop]]) -> integer -- return first index of value. Raises ValueError if the value is not present.
insert     L.insert(index, object) -- insert object before index
pop        L.pop([index]) -> item -- remove and return item at index (default last). Raises IndexError if list is empty or index is out of range.
remove     L.remove(value) -- remove first occurrence of value. Raises ValueError if the value is not present.
reverse    L.reverse() -- reverse *IN PLACE*
sort       L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*; cmp(x, y) -> -1, 0, 1
>>> import odbchelper
>>> info(odbchelper)
buildConnectionString Build a connection string from a dictionary Returns string.
>>> info(odbchelper, 30, 0)
buildConnectionString          Build a connection string from a dictionary
    
    Returns string.

举例:对一个tuple查找可以进行相关操作的函数

from apihelper import info
>>> li = ()
>>> info(li)
__add__    x.__add__(y) <==> x+y
__class__  tuple() -> empty tuple tuple(iterable) -> tuple initialized from iterable's items If the argument is a tuple, the return value is the same object.
__contains__ x.__contains__(y) <==> y in x
__delattr__ x.__delattr__('name') <==> del x.name
__eq__     x.__eq__(y) <==> x==y
__format__ default object formatter
__ge__     x.__ge__(y) <==> x>=y
__getattribute__ x.__getattribute__('name') <==> x.name
__getitem__ x.__getitem__(y) <==> x[y]
__getnewargs__ None
__getslice__ x.__getslice__(i, j) <==> x[i:j] Use of negative indices is not supported.
__gt__     x.__gt__(y) <==> x>y
__hash__   x.__hash__() <==> hash(x)
__init__   x.__init__(...) initializes x; see help(type(x)) for signature
__iter__   x.__iter__() <==> iter(x)
__le__     x.__le__(y) <==> x<=y
__len__    x.__len__() <==> len(x)
__lt__     x.__lt__(y) <==> x<y
__mul__    x.__mul__(n) <==> x*n
__ne__     x.__ne__(y) <==> x!=y
__new__    T.__new__(S, ...) -> a new object with type S, a subtype of T
__reduce__ helper for pickle
__reduce_ex__ helper for pickle
__repr__   x.__repr__() <==> repr(x)
__rmul__   x.__rmul__(n) <==> n*x
__setattr__ x.__setattr__('name', value) <==> x.name = value
__sizeof__ T.__sizeof__() -- size of T in memory, in bytes
__str__    x.__str__() <==> str(x)
__subclasshook__ Abstract classes can override this to customize issubclass(). This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
count      T.count(value) -> integer -- return number of occurrences of value
index      T.index(value, [start, [stop]]) -> integer -- return first index of value. Raises ValueError if the value is not present.
>>>
2.2 type / str / dir

>>> type(1)           1
<type 'int'>
>>> li = []
>>> type(li)          2
<type 'list'>
>>> import odbchelper
>>> type(odbchelper)  3
<type 'module'>
>>> import types      4
>>> type(odbchelper) == types.ModuleType
True
1type 可以接收任何东西作为参数――我的意思是任何东西――并返回它的数据类型。整型、字符串、列表、字典、元组、函数、类、模块,甚至类型对象都可以作为参数被 type 函数接受。
2type 可以接收变量作为参数,并返回它的数据类型。
3type 还可以作用于模块。
4你可以使用 types 模块中的常量来进行对象类型的比较。这就是 info 函数所做的,很快你就会看到。

str 将数据强制转换为字符串。每种数据类型都可以强制转换为字符串。str 还允许作用于模块;

>>> a = 123456
>>> str (a)
'123456'
>>> b = str (a)
>>> b
'123456'
>>> a
123456
>>> list = ['123', '456','789','python']
>>> list
['123', '456', '789', 'python']
>>> b = str(list)
>>> b
"['123', '456', '789', 'python']"
>>> tuple = ('123', '456','789','python')
>>> tuple
('123', '456', '789', 'python')
>>> b = str(tuple)
>>> b
"('123', '456', '789', 'python')"
>>> tuple = (123, 456,789,python)            # 元组内元素python类型无法确定,报错,

Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    tuple = (123, 456,789,python)
NameError: name 'python' is not defined
>>> tuple = (123, 456,789)
>>> tuple = (123, 456,789,'python' # 字符串写法,否则报未定义错误
>>> b = str(tuple)
>>> b
"(123, 456, 789, 'python')"
>>>
>>> type(tuple[0])
<type 'int'>
>>> type(tuple[3])
<type 'str'>

 tuple = (abc, der, python)              # 有此用法,但元素需要先定义

Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    tuple = (abc, der, python)
NameError: name 'abc' is not defined

info 函数的核心是强大的 dir 函数。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']
1li 是一个列表,所以 dir(li) 返回一个包含所有列表方法的列表。注意返回的列表只包含了字符串形式的方法名称,而不是方法对象本身。
2d 是一个字典,所以 dir(d) 返回字典方法的名称列表。其中至少有一个方法,keys,看起来还是挺熟悉的。
3这里就是真正变得有趣的地方。odbchelper 是一个模块,所以 dir(odbchelper) 返回模块中定义的所有部件的列表,包括内置的属性,例如 __name____doc__,以及其它你所定义的属性和方法。在这个例子中,odbchelper 只有一个用户定义的方法,就是在第 2 章中论述的 buildConnectionString 函数。

callable 函数,它接收任何对象作为参数,如果参数对象是可调用的,返回 True;否则返回 False。可调用对象包括函数、类方法,甚至类自身

>>> 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
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)
1string 模块中的函数现在已经不赞成使用了 (尽管很多人现在仍然还在使用 join 函数),但是在这个模块中包含了许多有用的变量,例如 string.punctuation,这个字符串包含了所有标准的标点符号字符。
2string.join 是一个用于连接字符串列表的函数。
3string.punctuation 是不可调用的对象;它是一个字符串。(字符串确有可调用的方法,但是字符串本身不是可调用的。)
4string.join 是可调用的;这个函数可以接受两个参数。
5任何可调用的对象都有 doc string。通过将 callable 函数作用于一个对象的每个属性,可以确定哪些属性 (方法、函数、类) 是你要关注的,哪些属性 (常量等等) 是你可以忽略、之前不需要知道的。









posted on 2022-07-05 18:14  我在全球村  阅读(67)  评论(0编辑  收藏  举报