Python:怎样通过阅读名字 “人眼” 判断其为对象的属性还是方法( 四 )


接下来讨论的是几个不常用到的内置对象类型。这些类型在正常的编码过程中应该很少接触,除非你正在自己实现一个解释器或开发环境之类。所以这里只列出一部分属性,如果需要一份完整的属性表或想进一步了解,可以查看文末列出的参考文档。2.8. 代码块(code)
代码块可以由类源代码、函数源代码或是一个简单的语句代码编译得到。这里我们只考虑它指代一个函数时的情况;2.5节中我们曾提到可以使用函数的func_code属性获取到它。code的属性全部是只读的。
co_argcount: 普通参数的总数,不包括*参数和**参数。 co_names: 所有的参数名(包括*参数和**参数)和局部变量名的元组。 co_varnames: 所有的局部变量名的元组。 co_filename: 源代码所在的文件名。 co_flags: 这是一个数值,每一个二进制位都包含了特定信息。较关注的是0b100(0×4)和0b1000(0×8),如果co_flags \u0026amp; 0b100 != 0,说明使用了*args参数;如果co_flags \u0026amp; 0b1000 != 0,说明使用了**kwargs参数。另外,如果co_flags \u0026amp; 0b100000(0×20) != 0,则说明这是一个生成器函数(generator function)。
?12345co = cat.sayHi.func_codeprint co.co_argcount # 1print co.co_names # (\u0026#39;name\u0026#39;,)print co.co_varnames # (\u0026#39;self\u0026#39;,)print co.co_flags \u0026amp; 0b100 # 0
2.9. 栈帧(frame)
栈帧表示程序运行时函数调用栈中的某一帧。函数没有属性可以获取它,因为它在函数调用时才会产生,而生成器则是由函数调用返回的,所以有属性指向栈帧。想要获得某个函数相关的栈帧,则必须在调用这个函数且这个函数尚未返回时获取。你可以使用sys模块的_getframe()函数、或inspect模块的currentframe()函数获取当前栈帧。这里列出来的属性全部是只读的。
f_back: 调用栈的前一帧。 f_code: 栈帧对应的code对象。 f_locals: 用在当前栈帧时与内建函数locals()相同,但你可以先获取其他帧然后使用这个属性获取那个帧的locals()。 f_globals: 用在当前栈帧时与内建函数globals()相同,但你可以先获取其他帧……。
?123456def add(x, y=1):f = inspect.currentframe()print f.f_locals # same as locals()print f.f_back # \u0026lt;frame object at 0x...\u0026gt;return x+yadd(2)
2.10. 追踪(traceback)
追踪是在出现异常时用于回溯的对象,与栈帧相反。由于异常时才会构建,而异常未捕获时会一直向外层栈帧抛出,所以需要使用try才能见到这个对象。你可以使用sys模块的exc_info()函数获得它,这个函数返回一个元组,元素分别是异常类型、异常对象、追踪。traceback的属性全部是只读的。
tb_next: 追踪的下一个追踪对象。 tb_frame: 当前追踪对应的栈帧。 tb_lineno: 当前追踪的行号。
?12345678def div(x, y):try:return x/yexcept:tb = sys.exc_info() # return (exc_type, exc_value, traceback)print tbprint tb.tb_lineno # "return x/y" 的行号div(1, 0)
3. 使用inspect模块
inspect模块提供了一系列函数用于帮助使用自省。下面仅列出较常用的一些函数,想获得全部的函数资料可以查看inspect模块的文档。3.1. 检查对象类型
is{module|class|function|method|builtin}(obj): 检查对象是否为模块、类、函数、方法、内建函数或方法。 isroutine(obj): 用于检查对象是否为函数、方法、内建函数或方法等等可调用类型。用这个方法会比多个is*()更方便,不过它的实现仍然是用了多个is*()。
?123im = cat.sayHiif inspect.isroutine(im):im()
对于实现了__call__的类实例,这个方法会返回False。如果目的是只要可以直接调用就需要是True的话,不妨使用isinstance(obj, collections.Callable)这种形式。我也不知道为什么Callable会在collections模块中,抱歉!我猜大概是因为collections模块中包含了很多其他的ABC(Abstract Base Class)的缘故吧:)


推荐阅读