2013-02-21 65 views
0

在此代码:Python 2.7版:奇怪的构造函数的行为:改变错误的领域

# coding=utf-8 


def print_tree(node, tree=0): 
    print(u"|---" * tree + u"-> %s" % node) 
    for kid in node.children: 
     print_tree(kid, tree + 1) 


class Person(object): 
    parent = None 
    first_name = None 
    last_name = None 
    children = [] 

    def __str__(self): 
     return '%s %s' % (self.first_name, self.last_name) 

    def __unicode__(self): 
     return u'%s %s' % (self.first_name, self.last_name) 

    def __init__(self, first_name, last_name, parent=None): 
     if parent is not None: 
      if not isinstance(parent, Person): 
       raise AttributeError('`parent` is not `Person` type!') 
      self.parent = parent 
      self.parent.children.append(self) 
     self.first_name = first_name 
     self.last_name = last_name 
     #self.children = [] 


root = Person('Alan', 'Smith') 
p1 = Person('Barbara', 'Smith', root) 
p2 = Person('Basia', 'Smith', root) 
p3 = Person('Bary', 'Smith', root) 

print_tree(root) 

如果我删除从#self.children = []例如评论工作正常。但我不明白为什么我必须添加这一行?

在调试器中我发现,线self.parent.children.append(self)增加self也为self.children

为什么?

回答

1

在python中,当你在类级声明一个属性时,它使它成为一个类属性(在类的所有实例之间共享)。在你的情况下,你需要实例属性。实例属性必须在构造函数中创建(您的self.children = [])。

+0

Lol,3年的自学Python,bilion代码行和你破坏了我的基本知识:D – WBAR 2013-02-21 15:35:28

+0

对不起;如果你使用过其他语言,这并不是非常明显,但它是有意义的(班级属性定义级别)。 – 2013-02-21 21:01:10

0

你有问题,因为在你的代码childrenclass variable(当你访问它的类级别是指,而不是实例级别),而不是一个instance variable(这是每个实例是唯一的)。每次__init__您的Person实例

self.children = [] 

所以,你必须添加的东西等等。

0

您正在引用对象实例的子对象,因此您不能仅将它保留在Class作用域/图层中。因此,你需要self.children = [],否则你不是指一个实例的孩子,而是班级'。 (而后者的语法是Person.children

+1

(2)不正确。他将“自我”添加到父母的“孩子”列表中,如果不是完全直观的阅读,这是完全有效的。 – 2013-02-21 15:29:48

+0

我的错误。我将删除这部分答案。谢谢你的收获! (这是我的问题:试着快速回答我的答案,错过了一个重要的细节!) – BlackVegetable 2013-02-21 15:30:46

2

children是一个类属性,你希望它是一个实例属性。您应该从班级范围中全部删除children=[],并且只留下__init__方法中的那个。