今天接触了下pyUSB,事先没看对象内部成员资料,直接用python的dir函数看了看pyUSB的内部构成。突然间想到自己可不可以写个简单的脚本,利用dir或其他函数遍历某个对象内部的所有成员,并打印出来成树状图的形式?于是写了如下对象分析程序:
使用方法 :
import matplotlib.pyplot as plt import AnalysisClass m = AnalysisClass.AnalysisClass() m.analysisObject(plt.Arrow, ‘plt.Arrow‘, ‘plt.txt‘, levelEnd=3)
调用analysisObject即可分析matplotlib的pyplot库内部的成员,并把所有成员函数、成员类以及各成员的__doc__前两行作为概述打印出来。上面的plt.Arrow是要分析的对象,’plt.Arrow’是要分析对象的名称字符串,’plt.txt’是用来保存分析结果的文件名,levelEnd用来指定递归的深度。
上面调用得到的结果:
省略若干行
代码概述:
程序核心很简单,就是递归地用dir()函数得到对象的所有成员,对于以下划线开头的内部成员不予处理,其他的如常量(一般全大写)、成员函数、成员类等的名字则保存起来,然后在以这些成员为对象递归地获取下一层的成员列表。
详细程序:
import types class AnalysisClass: def __init__(self): self.level= 0 self.file = None self.constNum=[] self.funcNum = [] def _levelTreePrint(self, strs, isConst=False): levelTab=self.level*4*‘ ‘ levelStrHead =[i for i in levelTab] if self.level != 0: # strs = str(self.funcNum[-1])+strs for i in range(self.level): if (not isConst) and self.funcNum[i] == 1: continue else: levelStrHead[i*4+1] = ‘|‘ levelStrHead[((self.level-1)*4+2):] = [‘-‘,‘-‘] levelStrHead = ‘‘.join(levelStrHead) levelStr = levelStrHead+strs else: levelStr = strs print levelStr if self.file != None: self.file.writelines(levelStr+‘\n‘) # def _isListOrTuple(self, cla): # if type(cla)==types.ListType or type(cla)==types.TupleType: # return True # else: # return False def _hasAvailableCla(self, cla): mems = dir(cla) constMem=[] claOrFuncMem = [] constMaxLen = 0 funcMaxLen = 0 for i in mems: lenI = len(i) if i[0] == ‘_‘: # No inner function or inner constants continue if i.isupper(): if lenI>constMaxLen: constMaxLen = lenI constMem.append(i) elif i[0:2]!=‘__‘ and i[-2:]!=‘__‘:# No buildin functions if lenI>funcMaxLen: funcMaxLen = lenI claOrFuncMem.append(i) return (constMem, constMaxLen, claOrFuncMem, funcMaxLen) def _printConstMem(self, cla, constMem, constMaxLen): loc_var = locals() for i in loc_var.iteritems(): if id(i[1]) == id(cla): cla_loc_name = i[0] for i in constMem: tmp = eval(cla_loc_name+‘.‘+i) i = i.ljust(constMaxLen+1, ‘ ‘) # if type(tmp)==types.IntType: # i = i+"(%d)"%tmp # else: # i = i+"(NOT AN INT NUMBER)"+str(type(tmp)) i = i + "(%s)"%str(tmp) self._levelTreePrint(i, isConst=True) self.constNum[-1] -= 1 def _printClaOrFuncMem(self,cla, cla_name, funcMaxLen, claOrFuncMem): loc_var = locals() for i in loc_var.iteritems(): if id(i[1]) == id(cla): cla_loc_name = i[0] for i in claOrFuncMem: iMem = cla_loc_name+‘.‘+i iMemReName = cla_name+‘.‘+i try: if None!=eval(iMem): self._analysisClass(eval(iMem),iMemReName, maxClaNameLen = funcMaxLen) self.level -= 1 else: self._levelTreePrint(cla_name.split(‘.‘)[-1]+‘.‘+i+"--‘Nothing‘") except Exception,e: pass self.funcNum[-1] -= 1 def _analysisClass(self, cla, cla_name, maxClaNameLen = 0): if hasattr(cla, "__doc__"): doc = str(cla.__doc__).split(‘\n‘) if len(doc)>=2: doc = doc[0]+doc[1] else: doc = doc[0] else: doc = ‘ ‘ if self.level!=0 and maxClaNameLen!=0: sNameTmp = cla_name.split(‘.‘) extraLen = len(sNameTmp[-2]) sName = sNameTmp[-2]+‘.‘+sNameTmp[-1] cla_name_tmp = sName.ljust(extraLen+maxClaNameLen+1,‘ ‘) else: cla_name_tmp = cla_name self._levelTreePrint(cla_name_tmp+‘:‘+str(type(cla))+3*‘-‘+"\""+doc+"\"") self.level += 1 if self.level == self.levelEnd: return (constMem, constMaxLen, claOrFuncMem, funcMaxLen) = self._hasAvailableCla(cla) if constMaxLen != 0: self.constNum.append(len(constMem)) self._printConstMem(cla, constMem, constMaxLen) self.constNum.pop() if funcMaxLen != 0: self.funcNum.append(len(claOrFuncMem)) self._printClaOrFuncMem(cla, cla_name, funcMaxLen, claOrFuncMem) self.funcNum.pop() else: return #=========================================================================== # Analysis the stucture of ‘obj‘.This function will list out the members of the object as # a tree. # @param obj - object,can be class,module,package,etc # @param obj_name - object name string,should be same to the actual name of ‘obj‘ # @param file_name - If you want to store the analysis info to a txt file,set this param # of your file name # @paramm levelEnd - set the recursion limits.The analysisObject function will recursively # enum all the members of the ‘obj‘,when the recursion depth equals levelEnd # the function will stop automatically # # Using: # import AnalysisClass # import matplotlib.pyplot as plt # m = AnalysisClass.AnalysisClass() # m.analysisObject(plt.Annotation, ‘plt.Annotation‘, ‘plt.txt‘, levelEnd=4) # Written by Liu.2014-07-25 #=========================================================================== def analysisObject(self, obj, obj_name, file_name=None, levelEnd=3): if file_name != None: self.file = open(file_name, ‘w‘) self.levelEnd = levelEnd self._analysisClass(obj, obj_name, levelEnd) if self.file !=None: self.file.close()