Mic*_*ert 6 python recursive-descent recursive-datastructures
我有一个复杂的Python数据结构(如果它很重要,它是一个很大的music21 Score对象),由于在对象结构内部某处存在弱化,它不会发痒.我以前用堆栈跟踪和python调试器调试过这样的问题,但总是很痛苦.是否有一个工具以递归方式对对象的所有属性运行dir(),查找隐藏在列表,元组,dicts等中的对象,并返回与特定值匹配的那些(lambda函数或类似的东西).一个很大的问题是递归引用,因此需要某种备忘录函数(如copy.deepcopy使用).我试过了:
import weakref
def findWeakRef(streamObj, memo=None):
weakRefList = []
if memo is None:
memo = {}
for x in dir(streamObj):
xValue = getattr(streamObj, x)
if id(xValue) in memo:
continue
else:
memo[id(xValue)] = True
if type(xValue) is weakref.ref:
weakRefList.append(x, xValue, streamObj)
if hasattr(xValue, "__iter__"):
for i in xValue:
if id(i) in memo:
pass
else:
memo[id(i)] = True
weakRefList.extend(findWeakRef(i), memo)
else:
weakRefList.extend(findWeakRef(xValue), memo)
return weakRefList
Run Code Online (Sandbox Code Playgroud)
我大概可以继续在此堵孔(在ITER是不是我想要什么类型的字典,例如),但在此之前我把更多的时间到了,如果有人知道一个更简单的回答不知道.它可能是一个非常有用的通用工具.
这是一个比较简单的解决方案,但有些幼稚。即只是在属性树下进行深度优先搜索。如果它是一个原始类型,则停止,否则深入树中。它将为您提供调用树和叶子的值。
def recursive_dir(obj, path):
if ((obj!=None) and (not isinstance(obj, (str,float,int,list,dict,set)))):
for attr, val in obj.__dict__.iteritems():
temp_path = path[:]
temp_path.append(attr)
recursive_dir(getattr(obj, attr), temp_path)
else:
print (path, "--->", obj)
print("")
recursive_dir(x,[])
Run Code Online (Sandbox Code Playgroud)
这似乎是一个答案的开始。我必须从 Python 3.2spect.getattr_static 向后移植一些项目才能使其工作,这样它就不会调用只是不断生成新对象的属性。这是我想出的代码:
\n\n#-------------------------------------------------------------------------------\n# Name: treeYield.py\n# Purpose: traverse a complex datastructure and yield elements\n# that fit a given criteria\n#\n# Authors: Michael Scott Cuthbert\n#\n# Copyright: Copyright \xc2\xa9 2012 Michael Scott Cuthbert\n# License: CC-BY\n#-------------------------------------------------------------------------------\nimport types\n\nclass TreeYielder(object):\n def __init__(self, yieldValue = None):\n \'\'\'\n `yieldValue` should be a lambda function that\n returns True/False or a function/method call that\n will be passed the value of a current attribute\n \'\'\' \n self.currentStack = []\n self.yieldValue = yieldValue\n self.stackVals = []\n t = types\n self.nonIterables = [t.IntType, t.StringType, t.UnicodeType, t.LongType,\n t.FloatType, t.NoneType, t.BooleanType]\n\n def run(self, obj, memo = None):\n \'\'\'\n traverse all attributes of an object looking\n for subObjects that meet a certain criteria.\n yield them.\n\n `memo` is a dictionary to keep track of objects\n that have already been seen\n\n The original object is added to the memo and\n also checked for yieldValue\n \'\'\'\n if memo is None:\n memo = {}\n self.memo = memo\n if id(obj) in self.memo:\n self.memo[id(obj)] += 1\n return\n else:\n self.memo[id(obj)] = 1\n\n if self.yieldValue(obj) is True:\n yield obj\n\n\n ### now check for sub values...\n self.currentStack.append(obj)\n\n tObj = type(obj)\n if tObj in self.nonIterables:\n pass\n elif tObj == types.DictType:\n for keyX in obj:\n dictTuple = (\'dict\', keyX)\n self.stackVals.append(dictTuple)\n x = obj[keyX]\n for z in self.run(x, memo=memo):\n yield z\n self.stackVals.pop()\n\n elif tObj in [types.ListType, types.TupleType]:\n for i,x in enumerate(obj):\n listTuple = (\'listLike\', i)\n self.stackVals.append(listTuple)\n for z in self.run(x, memo=memo):\n yield z\n self.stackVals.pop()\n\n else: # objects or uncaught types...\n ### from http://bugs.python.org/file18699/static.py\n try:\n instance_dict = object.__getattribute__(obj, "__dict__")\n except AttributeError:\n ## probably uncaught static object\n return\n\n for x in instance_dict:\n try:\n gotValue = object.__getattribute__(obj, x)\n except: # ?? property that relies on something else being set.\n continue\n objTuple = (\'getattr\', x)\n self.stackVals.append(objTuple)\n try:\n for z in self.run(gotValue, memo=memo):\n yield z\n except RuntimeError:\n raise Exception("Maximum recursion on:\\n%s" % self.currentLevel())\n self.stackVals.pop() \n\n self.currentStack.pop()\n\n def currentLevel(self):\n currentStr = ""\n for stackType, stackValue in self.stackVals:\n if stackType == \'dict\':\n if isinstance(stackValue, str):\n currentStr += "[\'" + stackValue + "\']"\n elif isinstance(stackValue, unicode):\n currentStr += "[u\'" + stackValue + "\']"\n else: # numeric key...\n currentStr += "[" + str(stackValue) + "]"\n elif stackType == \'listLike\':\n currentStr += "[" + str(stackValue) + "]"\n elif stackType == \'getattr\':\n currentStr += ".__getattribute__(\'" + stackValue + "\')"\n else:\n raise Exception("Cannot get attribute of type %s" % stackType)\n return currentStr\nRun Code Online (Sandbox Code Playgroud)\n\n此代码可让您运行如下所示的代码:
\n\nclass Mock(object):\n def __init__(self, mockThing, embedMock = True):\n self.abby = 30\n self.mocker = mockThing\n self.mockList = [mockThing, mockThing, 40]\n self.embeddedMock = None\n if embedMock is True:\n self.embeddedMock = Mock(mockThing, embedMock = False)\n\nmockType = lambda x: x.__class__.__name__ == \'Mock\'\n\nsubList = [100, 60, -2]\nmyList = [5, 20, [5, 12, 17], 30, {\'hello\': 10, \'goodbye\': 22, \'mock\': Mock(subList)}, -20, Mock(subList)]\nmyList.append(myList)\n\nty = TreeYielder(mockType)\nfor val in ty.run(myList):\n print(val, ty.currentLevel())\nRun Code Online (Sandbox Code Playgroud)\n\n并得到:
\n\n(<__main__.Mock object at 0x01DEBD10>, "[4][\'mock\']")\n(<__main__.Mock object at 0x01DEF370>, "[4][\'mock\'].__getattribute__(\'embeddedMock\')")\n(<__main__.Mock object at 0x01DEF390>, \'[6]\')\n(<__main__.Mock object at 0x01DEF3B0>, "[6].__getattribute__(\'embeddedMock\')")\nRun Code Online (Sandbox Code Playgroud)\n\n或者运行:
\n\nhigh = lambda x: isinstance(x, (int, float)) and x > 10\nty = TreeYielder(high)\nfor val in ty.run(myList):\n print(val, ty.currentLevel())\nRun Code Online (Sandbox Code Playgroud)\n\n并得到:
\n\n(20, \'[1]\')\n(12, \'[2][1]\')\n(17, \'[2][2]\')\n(30, \'[3]\')\n(22, "[4][\'goodbye\']")\n(100, "[4][\'mock\'].__getattribute__(\'embeddedMock\').__getattribute__(\'mocker\')[0]")\n(60, "[4][\'mock\'].__getattribute__(\'embeddedMock\').__getattribute__(\'mocker\')[1]")\n(40, "[4][\'mock\'].__getattribute__(\'embeddedMock\').__getattribute__(\'mockList\')[2]")\nRun Code Online (Sandbox Code Playgroud)\n\n我仍在试图找出为什么没有找到 .abby,但我认为即使在这一点上它也值得发布,因为它比我开始时更走在正确的轨道上。
\n