我究竟做错了什么?

What am I doing wrong? Python object instantiation keeping data from previous instantiation?

有人能告诉我我做错了什么或者我的理解哪里错了吗?

在我看来,下面用来实例化两个对象的代码应该为每个实例化都有单独的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Node:
    def __init__(self, data = []):
        self.data = data

def main():
    a = Node()
    a.data.append('a-data') #only append data to the a instance

    b = Node() #shouldn't this be empty?

    #a data is as expected
    print('number of items in a:', len(a.data))
    for item in a.data:
        print(item)

    #b data includes the data from a
    print('number of items in b:', len(b.data))
    for item in b.data:
        print(item)

if __name__ == '__main__':
    main()

但是,第二个对象是用第一个对象的数据创建的:

1
2
3
4
5
>>>
number of items in a: 1
a-data
number of items in b: 1
a-data


不能将可变对象用作默认值。所有对象将共享相同的可变对象。

这样做。

1
2
3
class Node:
    def __init__(self, data = None):
        self.data = data if data is not None else []

创建类定义时,它会创建[]列表对象。每次创建类的实例时,它都使用与默认值相同的列表对象。


问题出在这一行:

1
def __init__(self, data = []):

当您编写data = []来设置一个空列表作为该参数的默认值时,python只创建一次列表,并且每次调用该方法时都使用相同的列表,而不使用显式data参数。在您的例子中,这发生在ab的创建中,因为您没有向任何一个构造函数提供一个明确的列表,所以ab都使用与它们的data列表相同的对象。您对其中一项所做的任何更改都将反映在另一项中。

为了解决这个问题,我建议将构造函数的第一行替换为

1
2
3
def __init__(self, data=None):
    if data is None:
        data = []


为函数或方法提供默认值时,通常希望提供不可变的对象。如果您提供一个空列表或一个空字典,那么最终将调用共享该对象的函数或方法。

一个好的解决方法是:

1
2
3
4
5
def __init__(self, data = None):
    if data == None:
        self.data = []
    else:
        self.data = data