Python是一門非常容易入門,但非常難以精通的一門編程語言渊跋。難在面向?qū)ο?繼承集合腊嗡、多態(tài)、組合等等)拾酝,難在抽象(設(shè)計模式)燕少,難在語法糖,難在元編程蒿囤,難在代碼可以非常非常靈活的組合客们。
當我遇到瓶頸需要通過閱讀大量框架代碼來提升編程水平的過程中,由于框架性代碼過于靈活或抽象,很多時候沒辦法僅通過閱讀源代碼就能理解底挫,而是需要加入日志去運行恒傻、調(diào)試來查看當前對象是什么類,當前對象有哪些屬性建邓,當前對象是被誰調(diào)用的盈厘。
下面分享兩個我在閱讀開源框架源碼時常用的分析工具:
裝飾器
查看調(diào)用者的文件位置路徑和代碼調(diào)用所在的行數(shù),通過這種方式我可以一層一層的追蹤代碼執(zhí)行的源頭在哪里官边。
也就是說一般使用它的場景是理解代碼線性處理過程沸手。
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())
輸出結(jié)果
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
參考網(wǎng)址:
Stansosleepy的簡書博客
?
?
?
?
?
?
內(nèi)省函數(shù)
很多時候開源框架的文檔并沒有細致到告訴你每一個方法是什么意思,怎么用注簿。
通常我在使用一個框架的某個組件功能時契吉,習(xí)慣看看調(diào)用某個方法返回的結(jié)果,并分析一下該結(jié)果對象中包含有哪些可調(diào)用的方法诡渴,每個方法綁定的是哪些類對象捐晶,通過這些屬性對象可以使我對整個框架的功能和理解更全面。
utils.py
# -.- coding:utf-8 -.-
from __future__ import print_function
class ObjectAttrs(object):
"""
一般用于調(diào)試某個對象時使用妄辩,當前這個工具類會將調(diào)試對象和其所屬的所有繼承對象的屬性依次羅列出來租悄。
變量 showed_list 它是一個類變量, 用于記錄已顯示過的對象.
使用方法:
ObjectAttrs.show(調(diào)試對象)
"""
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: 內(nèi)部使用的參數(shù), 用來傳遞_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: 僅顯示對象的所有繼承關(guān)系
import utils
utils.ObjectAttrs.show(Fox(), show_attr=False)
# 輸出結(jié)果
<__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)
# 輸出結(jié)果
<__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: 顯示當前對象的所有屬性 以及 顯示當前對象所有繼承關(guān)系
import utils
utils.ObjectAttrs.show(Fox())
# 輸出結(jié)果
<__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>