# -*- coding: cp932 -*- # # オブジェクトや名前空間の参照関係を可視化するライブラリ # showNamespace(g)とshowNamespaceAsGraph(g)は引数としてglobals()、 # showObj(o)とshowObjAsGraph(o)はその他のオブジェクトが渡されることを前提にしています DEFAULT_GLOBALS=globals() DEFAULT_GLOBALS["DEFAULT_GLOBALS"]=DEFAULT_GLOBALS # グラフでの可視化に使うGraphVisのdot.exeの場所 # *AsGraphを使う場合は環境に合わせて書き換える必要があります。 dotpos=r"C:\PROGRA~1\ATT\Graphviz\bin\dot.exe" # 出力するフォーマット dottyp="png" def purifyNamespace(g): """引数に渡された辞書を名前空間とみなして、初学者が当惑しそうなものを隠す""" for k in g.keys(): # 元からあるものをとりのぞく if DEFAULT_GLOBALS.has_key(k): if DEFAULT_GLOBALS[k]==g[k]: continue # _で始まるものをとりのぞく(オプショナルにするべき?) if k[0]=="_": continue # 自分と思しきものをとりのぞく if k=="pyObjVis": continue yield (k, g[k]) def wait(): """表示後の待機""" raw_input("改行キーを押すと続行します...") def showNamespace(g): objects=[] for (key, value) in purifyNamespace(g): print "変数名「%s」:" % key print indent(str(factory(value, objects))) wait() def showNamespaceAsGraph(g): tmp={} for (key, value) in purifyNamespace(g): tmp[key]=value showObjAsGraph(tmp) def showObj(o): objects=[] result=factory(o, objects) print result wait() def showObjAsGraph(o): objects=[] result=factory(o, objects) fo=open("tmp.dot","w") fo.write("""digraph structs { graph [rankdir = "LR"]; node [shape=record];""") for o in objects: fo.write("%s\n" % o.getDotVertex()) for o in objects: for e in o.edges: fo.write("%s\n" % e) fo.write("}") fo.close() import os os.system(dotpos+" -T%s tmp.dot -o tmp.%s"%(dottyp,dottyp)) os.system("tmp.%s"%dottyp) wait() def indent(str): """与えられた文字列をインデントする""" return "\n".join(["\t%s"%line for line in str.split("\n")]) # タイプの日本語表記 typJa={ "str":"文字列", "int":"整数", "float":"実数", "tuple":"タプル", "list":"リスト", "dict":"辞書", "function":"関数", "builtin_function_or_method":"組み込み関数", "module":"モジュール" } def factory(value, objects): typ=type(value).__name__ if typ=="str": cls=SingleLine elif typ=="int": cls=SingleLine elif typ=="float": cls=SingleLine elif typ=="tuple": cls=ListLike elif typ=="list": cls=ListLike elif typ=="dict": cls=DictLike elif typ=="function": cls=FuncLike elif typ=="builtin_function_or_method": cls=FuncLike elif typ=="module": cls=FuncLike else: cls=SingleLine obj = cls(value, typ, objects) return obj class ObjWrapper: def __init__(self, value, typ, objects): objects.append(self) self.id=len(objects) self.value=value self.type=typ strExpr="タイプ:" if typJa.has_key(typ): strExpr+="%s(%s)"%(typJa[typ], typ) else: strExpr+=typ self.strExpr=[strExpr] self.vertex = ['obj%d [shape=record, label="' % self.id] self.vertex.append("%s" % typ) self.edges=[] def __str__(self): return "\n".join(self.strExpr) def getDotVertex(self): return "".join(self.vertex) def getDotEdges(self): return self.edges class SingleLine(ObjWrapper): def __init__(self, value, typ, objects): ObjWrapper.__init__(self, value, typ, objects) self.strExpr.append("値:%s"%repr(value)) self.vertex.append('|%s"];'%repr(value)) class ListLike(ObjWrapper): def __init__(self, value, typ, objects): ObjWrapper.__init__(self, value, typ, objects) for i in range(len(value)): self.strExpr.append("%d番目の値:"%i) for o in objects: if o.value is value[i]: self.strExpr.append(indent("**木構造ではないため表示できません**")) break else: o=factory(value[i], objects) self.strExpr.append(indent(str(o))) self.vertex.append("|%dth"%(i+1, i)) self.edges.append("obj%d:f%d -> obj%d;"%(self.id, i+1, o.id)) self.vertex.append('"];') class DictLike(ObjWrapper): def __init__(self, value, typ, objects): ObjWrapper.__init__(self, value, typ, objects) for i in range(len(value)): k=value.keys()[i] self.strExpr.append("キー「%s」に対応する値:"%k) for o in objects: if o.value is value[k]: self.strExpr.append(indent("**木構造ではないため表示できません**")) break else: o=factory(value[k], objects) self.strExpr.append(indent(str(o))) self.vertex.append("|key: %s"%(i+1, repr(k))) self.edges.append("obj%d:f%d -> obj%d;"%(self.id, i+1, o.id)) self.vertex.append('"];') class FuncLike(ObjWrapper): def __init__(self, value, typ, objects): ObjWrapper.__init__(self, value, typ, objects) self.strExpr.append("名前:%s"%value.__name__) self.vertex.append('|name:%s"];'%value.__name__)