0

我对在 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

谢谢!

4

3 回答 3

2

正如其他人所建议的那样,这看起来像一棵树(或图)遍历

您可能想查看递归算法。例如:

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为:

  1. 对对象的内部状态做一些事情
  2. 处理任何X依赖对象(例如它的孩子(ren))

- 编辑 -

关于您仅更新最后一个值的最后评论(对于树,这称为叶子):您有两种解决方案:

一种是为所有图形使用相同类型的节点,并将叶子定义为“没有子节点的节点”:

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)])])])

前者允许动态叶子(即您可以稍后将新子节点添加到叶子,这使它们不再是叶子),而如果您的树节点和叶子本质上不同(例如,对于文件系统,您的叶子所在的位置),后者更有意义文件和树是一个目录结构)。这真的取决于你的问题来选择哪个是最好的。

于 2013-10-16T17:27:35.443 回答
0

我不太确定您要做什么,我必须猜测您的课程TestClassBranchLength外观。(在我的示例中它们是相同的,但在您的代码中肯定不是)。

也许你正在寻找这样的东西:

#! /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)
于 2013-10-16T17:26:06.493 回答
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')

...并让其中的每个子分支都更新为适当的值。

于 2013-10-16T17:29:10.880 回答