我很擅长在Python中使用OOP。 我有一个问题要解决,我能够部分地解决它。如果我不能非常清楚地表达我的问题,那就很抱歉。
如果我创建类test
的对象ClassTest
并输入Python
test.__dict__
我将得到以下结果:
{'W0': 41.95659301705824, 'right': 'Seq1', 'W1': 86.66314873856487, 'left': <__main__.BranchLength object at 0x1083f8110>}
如果我再次输入:
test.left.__dict__
我会:
{'W0': 86.66314873856487, 'right': 'Seq2', 'W': 41.95659301705824, 'left': <__main__.BranchLength object at 0x1083f8150>}
依旧......
有没有办法以交互方式访问left
的所有实例(?)?我有兴趣更改W0
的所有值,例如。
谢谢!
答案 0 :(得分:2)
正如其他人所说,这看起来像tree (or a graph) traversal。
您可能需要查看recursive algorithms。例如:
class A(object):
def __init__(self, x, child = None):
self.x = x
self.child = child
def increments(self):
self.x += 1 # increment this one
# Check that the child is not 'None' or some other value
if hasattr(self.child, 'increments'):
# recursively increment the child
self.child.increments()
def __repr__(self):
# friendly representation
return 'A(%r, %r)' % (self.x, self.child)
>>> a = A(1, A(2, A(3, A(4))))
>>> a
A(1, A(2, A(3, A(4, None))))
>>> a.increments()
>>> a
A(2, A(3, A(4, A(5, None))))
>>> a.increments()
>>> a
A(3, A(4, A(5, A(6, None))))
基本上,您将递归函数X
定义为:
X
醇>
- 编辑 -
关于您最后一条仅更新最后一个值的评论(对于树,这称为 leaf ):您有两个解决方案:
一个是为你的所有图形提供相同类型的节点,并将叶子定义为“没有子节点的节点”:
class Node(object):
def __init__(self, x, *children):
self.x = x
self.children = []
if children:
self.children.extend(children)
def updateLeafs(self, newx):
if self.children:
# This node has children: it is not a Leaf
for c in self.children:
c.updateLeafs(newx)
else:
# This node has no children -> Definition of a leaf !
self.x = newx
def __str__(self):
"Pretty printing of the tree"
if self.children:
# A node
return 'Node(%s -> [%s])' % (repr(self.x), ','.join(str(c) for c in self.children))
else:
# A leaf
return 'Node(%s)' % repr(self.x)
你得到:
>>> tree = Node(1, Node(4, Node(4, Node(4), Node(5)), Node(6), Node(7, Node(8))))
>>> print tree
Node(1 -> [Node(4 -> [Node(4 -> [Node(4),Node(5)]),Node(6),Node(7 -> [Node(8)])])])
>>> tree.updateLeafs(10)
>>> print tree
Node(1 -> [Node(4 -> [Node(4 -> [Node(10),Node(10)]),Node(10),Node(7 -> [Node(10)])])])
另一种可能性是为你的叶子和树枝设置不同的类型:
class Branch(object):
def __init__(self, *children):
self.children = children
def update(self, newx):
for c in self.children:
c.update(newx)
def __str__(self):
"Pretty printing of the tree"
return 'Branch([%s])' % (','.join(str(c) for c in self.children))
class Leaf(object):
def __init__(self, x):
self.x = x
def update(self, newx):
self.x = newx
def __str__(self):
return 'Leaf(%s)' % self.x
这会产生:
>>> tree = Branch(Branch(Branch(Leaf(4), Leaf(5)), Leaf(6), Branch(Leaf(8))))
>>> print tree
Branch([Branch([Branch([Leaf(4),Leaf(5)]),Leaf(6),Branch([Leaf(8)])])])
>>> tree.update(10)
>>> print tree
Branch([Branch([Branch([Leaf(10),Leaf(10)]),Leaf(10),Branch([Leaf(10)])])])
前者允许动态叶子(即你可以在以后添加新的子叶子,这使得它们不再是叶子),而后者更有意义,如果你的树节点和叶子本质上是不同的(例如对于文件系统,你的叶子是文件,树是目录结构)。这真的取决于你的问题,选择哪个是最好的。
答案 1 :(得分:0)
我不太确定你要做什么,我必须猜测你的班级TestClass
和BranchLength
是什么样的。 (在我的例子中,它们是相同的,但在你的代码中肯定不是)。
也许你正在寻找这样的东西:
#! /usr/bin/python3
class TestClass:
def __init__ (self, W0, left):
self.W0, self.left = W0, left
def updateW0 (self, f):
self.W0 = f (self.W0)
if self.left and hasattr (self.left, 'updateW0'):
self.left.updateW0 (f)
class BranchLength:
def __init__ (self, W0, left):
self.W0, self.left = W0, left
def updateW0 (self, f):
self.W0 = f (self.W0)
if self.left and hasattr (self.left, 'updateW0'):
self.left.updateW0 (f)
b0 = BranchLength ('branch zero', None)
b1 = BranchLength ('branch one', b0)
b2 = BranchLength ('branch two', b1)
test = TestClass ('the test', b2)
for x in [b0, b1, b2, test]: print (x.W0)
test.updateW0 (lambda x: '{} {}'.format (x, x) ) #whatever update you need
for x in [b0, b1, b2, test]: print (x.W0)
答案 2 :(得分:0)
嗯,你有两个可能的解决方案。您可以尝试将TestClass
类的每个实例保留在列表中,除了您现在如何嵌套它们之外,还可以遍历列表以对所有这些实例执行相同的操作。
这有点笨拙,更好的解决方案可能是从“顶级对象”开始,并使用递归遍历树,随时操作每个实例。例如:
def change_attr(tree, target, new_val):
setattr(tree, target, new_val)
# essentially the same as doing `tree.__dict__[target] = new_val`
if tree.left is None:
return
else:
change_attr(tree.left, target, new_val)
然后,您可以通过调用
将TestClass
类的实例传入函数
change_attr(test, 'W0', 'foobar')
...并让其中的每个子分支更新为适当的值。