Python是一门非常容易入门,但非常难以精通的一门编程语言。难在面向对象(继承集合、多态、组合等等),难在抽象(设计模式),难在语法糖,难在元编程,难在代码可以非常非常灵活的组合。
当我遇到瓶颈需要通过阅读大量框架代码来提升编程水平的过程中,由于框架性代码过于灵活或抽象,很多时候没办法仅通过阅读源代码就能理解,而是需要加入日志去运行、调试来查看当前对象是什么类,当前对象有哪些属性,当前对象是被谁调用的。
下面分享两个我在阅读开源框架源码时常用的分析工具:
装饰器
查看调用者的文件位置路径和代码调用所在的行数,通过这种方式我可以一层一层的追踪代码执行的源头在哪里。
也就是说一般使用它的场景是理解代码线性处理过程。
utils.py
# -.- coding:utf-8 -.-
from __future__ import print_function
def findcaller(func):
def wrapper(*args,**kwargs):
import sys
f=sys._getframe()
filename=f.f_back.f_code.co_filename
lineno=f.f_back.f_lineno
print('{} {!s:<20} {} {} {} {} {}'.format(func.func_name, 'Called By ', filename, '', lineno, args, kwargs))
return func(*args,**kwargs)
return wrapper
使用方法
earth.py
# -.- coding:utf-8 -.-
import utils
@utils.findcaller
def golden():
return 'metal'
@utils.findcaller
def wood():
return golden()
@utils.findcaller
def water():
return wood()
@utils.findcaller
def fire():
return water()
@utils.findcaller
def land():
return fire()
print(land())
输出结果
land Called By C:/Users/zhengtong/earth.py 31 () {}
fire Called By C:/Users/zhengtong/earth.py 28 () {}
water Called By C:/Users/zhengtong/earth.py 23 () {}
wood Called By C:/Users/zhengtong/earth.py 18 () {}
golden Called By C:/Users/zhengtong/earth.py 13 () {}
metal
参考网址:
Stansosleepy的简书博客
内省函数
很多时候开源框架的文档并没有细致到告诉你每一个方法是什么意思,怎么用。
通常我在使用一个框架的某个组件功能时,习惯看看调用某个方法返回的结果,并分析一下该结果对象中包含有哪些可调用的方法,每个方法绑定的是哪些类对象,通过这些属性对象可以使我对整个框架的功能和理解更全面。
utils.py
# -.- coding:utf-8 -.-
from __future__ import print_function
class ObjectAttrs(object):
"""
一般用于调试某个对象时使用,当前这个工具类会将调试对象和其所属的所有继承对象的属性依次罗列出来。
变量 showed_list 它是一个类变量, 用于记录已显示过的对象.
使用方法:
ObjectAttrs.show(调试对象)
"""
showed_list = []
@classmethod
def show(cls, _class, show_attr=True, show_doc=False, _parent_class=None):
"""
:param _class: 必填, 任意对象.
:param show_attr: 是否显示_class对象的所有attribute.
:param show_doc: 是否显示_class对象的__doc__属性.
:param _parent_class: 内部使用的参数, 用来传递_class对象的父类.
:return:
"""
def _show(class_name):
if class_name in cls.showed_list:
return
else:
cls.showed_list.append(class_name)
parent_class_name = ' inherited by {}'.format(_parent_class) if _parent_class else ''
blank_lines = '\n' * 5 if show_attr else ''
print(blank_lines, class_name, parent_class_name, sep='')
if not show_attr: return
for x in dir(class_name):
if not show_doc:
if x == '__doc__':
continue
try:
attr_name = x
attr_type = type(getattr(class_name, attr_name))
attr_object = getattr(class_name, attr_name)
print('{!s:<60}{!s:<60}{}'.format(attr_name, attr_type, attr_object))
except:
print('{!s:<60}{}'.format(attr_name, 'error'))
_show(class_name=_class)
parents = list(getattr(_class, '__bases__', ''))
parents.append(getattr(_class, '__class__', ''))
parents = [i for i in parents if i is not object and i is not type and i]
for i in parents:
cls.show(_class=i, _parent_class=_class, show_doc=show_doc, show_attr=show_attr)
源代码文件
fox.py
# -.- coding:utf-8 -.-
import utils
class Base(object):
def breathe(self):
return 'breathe'
class Animal(Base):
def run(self):
return 'run'
def walk(self):
return 'walk'
def sleep(self):
return 'sleep'
class FoxManager(object):
def find_other_fox(self):
return 'find_other_fox'
def drink(self):
return 'drink water'
def eat(self):
return 'eat meat'
class Fox(Base):
def __init__(self):
self.name = 'aurora fox'
self.sex = 'male'
self.actions = FoxManager()
使用方法1: 仅显示对象的所有继承关系
import utils
utils.ObjectAttrs.show(Fox(), show_attr=False)
# 输出结果
<__main__.Fox object at 0x035D2B30>
<class '__main__.Fox'> inherited by <__main__.Fox object at 0x035D2B30>
<class '__main__.Base'> inherited by <class '__main__.Fox'>
使用方法2: 仅显示当前对象的所有属性
import utils
utils.ObjectAttrs.show(Fox(), show_parent=False)
# 输出结果
<__main__.Fox object at 0x030F2910>
__class__ <type 'type'> <class '__main__.Fox'>
__delattr__ error
__dict__ <type 'dict'> {'name': 'aurora fox', 'actions': <__main__.FoxManager object at 0x030F2F50>, 'sex': 'male'}
__format__ <type 'builtin_function_or_method'> <built-in method __format__ of Fox object at 0x030F2910>
__getattribute__ error
__hash__ error
__init__ <type 'instancemethod'> <bound method Fox.__init__ of <__main__.Fox object at 0x030F2910>>
__module__ <type 'str'> __main__
__new__ <type 'builtin_function_or_method'> <built-in method __new__ of type object at 0x51FA68B8>
__reduce__ <type 'builtin_function_or_method'> <built-in method __reduce__ of Fox object at 0x030F2910>
__reduce_ex__ <type 'builtin_function_or_method'> <built-in method __reduce_ex__ of Fox object at 0x030F2910>
__repr__ error
__setattr__ error
__sizeof__ <type 'builtin_function_or_method'> <built-in method __sizeof__ of Fox object at 0x030F2910>
__str__ error
__subclasshook__ <type 'builtin_function_or_method'> <built-in method __subclasshook__ of type object at 0x030F9968>
__weakref__ <type 'NoneType'> None
actions <class '__main__.FoxManager'> <__main__.FoxManager object at 0x030F2F50>
name <type 'str'> aurora fox
run <type 'instancemethod'> <bound method Fox.run of <__main__.Fox object at 0x030F2910>>
sex <type 'str'> male
sleep <type 'instancemethod'> <bound method Fox.sleep of <__main__.Fox object at 0x030F2910>>
walk <type 'instancemethod'> <bound method Fox.walk of <__main__.Fox object at 0x030F2910>>
使用方法3: 显示当前对象的所有属性 以及 显示当前对象所有继承关系
import utils
utils.ObjectAttrs.show(Fox())
# 输出结果
<__main__.Fox object at 0x02ED2B50>
__class__ <type 'type'> <class '__main__.Fox'>
__delattr__ error
__dict__ <type 'dict'> {'name': 'aurora fox', 'actions': <__main__.FoxManager object at 0x02ED2F50>, 'sex': 'male'}
__format__ <type 'builtin_function_or_method'> <built-in method __format__ of Fox object at 0x02ED2B50>
__getattribute__ error
__hash__ error
__init__ <type 'instancemethod'> <bound method Fox.__init__ of <__main__.Fox object at 0x02ED2B50>>
__module__ <type 'str'> __main__
__new__ <type 'builtin_function_or_method'> <built-in method __new__ of type object at 0x51FA68B8>
__reduce__ <type 'builtin_function_or_method'> <built-in method __reduce__ of Fox object at 0x02ED2B50>
__reduce_ex__ <type 'builtin_function_or_method'> <built-in method __reduce_ex__ of Fox object at 0x02ED2B50>
__repr__ error
__setattr__ error
__sizeof__ <type 'builtin_function_or_method'> <built-in method __sizeof__ of Fox object at 0x02ED2B50>
__str__ error
__subclasshook__ <type 'builtin_function_or_method'> <built-in method __subclasshook__ of type object at 0x02ED9968>
__weakref__ <type 'NoneType'> None
actions <class '__main__.FoxManager'> <__main__.FoxManager object at 0x02ED2F50>
name <type 'str'> aurora fox
run <type 'instancemethod'> <bound method Fox.run of <__main__.Fox object at 0x02ED2B50>>
sex <type 'str'> male
sleep <type 'instancemethod'> <bound method Fox.sleep of <__main__.Fox object at 0x02ED2B50>>
walk <type 'instancemethod'> <bound method Fox.walk of <__main__.Fox object at 0x02ED2B50>>
<class '__main__.Fox'> inherited by <__main__.Fox object at 0x02ED2B50>
__class__ <type 'type'> <type 'type'>
__delattr__ <type 'wrapper_descriptor'> <slot wrapper '__delattr__' of 'object' objects>
__dict__ <type 'dictproxy'> {'__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x02ECBCB0>}
__format__ error
__getattribute__ <type 'wrapper_descriptor'> <slot wrapper '__getattribute__' of 'object' objects>
__hash__ <type 'wrapper_descriptor'> <slot wrapper '__hash__' of 'object' objects>
__init__ <type 'instancemethod'> <unbound method Fox.__init__>
__module__ <type 'str'> __main__
__new__ <type 'builtin_function_or_method'> <built-in method __new__ of type object at 0x51FA68B8>
__reduce__ error
__reduce_ex__ error
__repr__ <type 'wrapper_descriptor'> <slot wrapper '__repr__' of 'object' objects>
__setattr__ <type 'wrapper_descriptor'> <slot wrapper '__setattr__' of 'object' objects>
__sizeof__ error
__str__ <type 'wrapper_descriptor'> <slot wrapper '__str__' of 'object' objects>
__subclasshook__ <type 'builtin_function_or_method'> <built-in method __subclasshook__ of type object at 0x02ED9968>
__weakref__ <type 'getset_descriptor'> <attribute '__weakref__' of 'Base' objects>
run <type 'instancemethod'> <unbound method Fox.run>
sleep <type 'instancemethod'> <unbound method Fox.sleep>
walk <type 'instancemethod'> <unbound method Fox.walk>
<class '__main__.Base'> inherited by <class '__main__.Fox'>
__class__ <type 'type'> <type 'type'>
__delattr__ <type 'wrapper_descriptor'> <slot wrapper '__delattr__' of 'object' objects>
__dict__ <type 'dictproxy'> {'__module__': '__main__', 'run': <function run at 0x02ECBBB0>, 'walk': <function walk at 0x02ECBBF0>, 'sleep': <function sleep at 0x02ECBC30>, '__dict__': <attribute '__dict__' of 'Base' objects>, '__weakref__': <attribute '__weakref__' of 'Base' objects>, '__doc__': None}
__format__ error
__getattribute__ <type 'wrapper_descriptor'> <slot wrapper '__getattribute__' of 'object' objects>
__hash__ <type 'wrapper_descriptor'> <slot wrapper '__hash__' of 'object' objects>
__init__ <type 'wrapper_descriptor'> <slot wrapper '__init__' of 'object' objects>
__module__ <type 'str'> __main__
__new__ <type 'builtin_function_or_method'> <built-in method __new__ of type object at 0x51FA68B8>
__reduce__ error
__reduce_ex__ error
__repr__ <type 'wrapper_descriptor'> <slot wrapper '__repr__' of 'object' objects>
__setattr__ <type 'wrapper_descriptor'> <slot wrapper '__setattr__' of 'object' objects>
__sizeof__ error
__str__ <type 'wrapper_descriptor'> <slot wrapper '__str__' of 'object' objects>
__subclasshook__ <type 'builtin_function_or_method'> <built-in method __subclasshook__ of type object at 0x02ED95B8>
__weakref__ <type 'getset_descriptor'> <attribute '__weakref__' of 'Base' objects>
run <type 'instancemethod'> <unbound method Base.run>
sleep <type 'instancemethod'> <unbound method Base.sleep>
walk <type 'instancemethod'> <unbound method Base.walk>