2010-03-08 151 views
5

假设你有这样的事情:Python实例和属性:这是一个错误还是我完全错了?

class intlist: 
     def __init__(self,l = []): 
       self.l = l 
     def add(self,a): 
       self.l.append(a) 

def appender(a): 
     obj = intlist() 
     obj.add(a) 
     print obj.l 

if __name__ == "__main__": 
     for i in range(5): 
       appender(i) 

一个函数创建intList中的实例,并在这个新的实例的方法追加在实例属性升调用。

如何产生该代码的输出是:

[0]

[0,1]

[0,1,2]

[0,1,2 ,3]

[0,1,2,3,4]

? 如果切换

obj = intlist() 

obj = intlist(l=[]) 

我得到所需的输出

[0]

[1]

[2]

[3]

[4]

为什么会发生这种情况?

感谢

+0

+1措辞这个这样的问题,并从一开始就承认错误。这就是我们学习的方式! :) – jathanism 2010-03-08 17:01:24

+0

相关:http://stackoverflow.com/questions/1011431/python-things-one-must-avoid – 2010-03-08 17:07:42

+0

谢谢大家,现在我明白了,我必须更多关注我作为默认值使用的内容。再次感谢:) – 2010-03-09 09:51:35

回答

14

啊,你已经打了常见的Python陷阱之一:默认值计算一次,然后重新使用。所以,每次调用__init__时,都会使用相同的列表。

这是做你想要什么样的Python的方式:

def __init__(self, l=None): 
    self.l = [] if l is None else l 

对于位的更多信息,(即标题后特别是约三段)退房the Python docs

编辑:有a much better description in another answer

+4

没错。一般来说,你可能不想使用可变类型作为默认值。 – prestomation 2010-03-08 16:44:31

+0

请注意:在我最初的回答中,我使用了'self.l = l或[]'......在这种情况下,这可能是正确的,但这是一个危险的习惯(例如:my_list = [] ; intlist(my_list); my_list.append(4)'可能不会做你想要的)。 – 2010-03-08 16:51:04

+0

+1:标准问题 - 可变对象作为默认值。看到所有这些解释:http://stackoverflow.com/search?q=%5Bpython%5D+mutable+default+values – 2010-03-08 17:06:33

1

行为的发生是因为你__init__方法共享所有调用相同的默认列表。

尝试:

class intlist: 
     def __init__(self, l): 
       self.l = l if (l is not None) else [] 
     def add(self,a): 
       self.l.append(a) 

编辑:使用is not,每SilentGhost

+0

'是'是'None'的惯用测试。 – SilentGhost 2010-03-08 16:44:16

3

的问题是,你说的

def __init__(self,l = []): 

当你告诉Python中使用相同的列表,[],为构造函数的每次调用。所以每次调用obj = intlist()时都会追加相同的列表。

您应该做的是将l设置为缺省值None,这是一个标量(因此,如果多次使用,您的代码将按预期工作)。然后,如果lNone,则将新类成员初始化为[]。否则,只需将成员变量分配给l即可。

0

请注意列表和字典等类型的默认参数。 intlist的每个实例从默认参数获取相同的列表对象。

4

当您在__init__中设置默认值l=[]时,您实际上每次都使用相同的列表。相反,你可以尝试像:

class intlist: 
    def __init__(self, l=None): 
     if l is None: 
      self.l = [] 
     else: 
      self.l = l 
+1

+ 1,'是无'是完全正确的方式来检查这里(不是'==没有'或仅仅根据'l'的真值作为其他答案的建议!)。 – 2010-03-08 16:44:59

1

obj = intlist()调用你__init__()功能,使用相同的数组类的每一个实例。

obj = intlist(l=[])为每个实例创建一个新数组。

相关问题