更新类中的所有对象

时间:2013-10-16 17:13:42

标签: python class oop

我很擅长在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的所有值,例如。

谢谢!

3 个答案:

答案 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定义为:

  1. 使用对象的内部状态执行某些操作
  2. 使用任何依赖对象(例如其子(ren))
  3. 执行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)

我不太确定你要做什么,我必须猜测你的班级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)

答案 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')

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