为什么在python 3类的实例中对列表的更改是全局的?

时间:2016-04-21 03:34:00

标签: python-3.x

为什么当我创建一个带有列表的类时,列表及其内容将变为全局

class A:
    my_list = []
    string = ""
    def add(self, data):
        self.string += "a"
        self.my_list.append(data)
    def print_list(self):
        print(self.string)
        print(self.my_list)

a = A()
b = A()
a.add("test")
a.print_list()
b.print_list()

a和b都将打印由a.add

创建的列表
# results of a.print_list
xa
['test']

# results of b.print_list
x
['test']

所以我的问题是,这对python3来说是正常的,还是一个bug。 对我来说,似乎只有全局修改了列表。

2 个答案:

答案 0 :(得分:1)

字符串是不可变的,所以

    self.string += "a"

创建一个新对象并将其绑定到self.string

这显然是在改变列表

    self.my_list.append(data)

也许更有趣的是

    self.my_list += [data]

也会改变列表

一般规则是__iadd__ 对可变对象和不可变对象的行为不同

答案 1 :(得分:1)

这是解释:

  

对象具有个性,多个名称(在多个范围内)可以绑定到同一个对象。这在其他语言中称为别名。乍一看Python时通常不会理解这一点,在处理不可变的基本类型(数字,字符串,元组)时可以安全地忽略它。但是,别名对包含可变对象(如列表,字典和大多数其他类型)的Python代码的语义可能会产生惊人的影响。这通常用于程序的好处,因为别名在某些方面表现得像指针。例如,传递一个对象很便宜,因为实现只传递一个指针;如果函数修改了作为参数传递的对象,调用者将看到更改 - 这消除了对Pascal中两个不同的参数传递机制的需要。

From oficial Python 3 docs

这就是解决方案:

  

(...)使用实例变量代替(...)

像这样:

class Dog:
    def __init__(self, name):
        self.name = name
        self.tricks = [] # creates a new empty list for each dog

    def add_trick(self, trick):
        self.tricks.append(trick)

上述代码的结果:

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks ['roll over']
>>> e.tricks ['play dead']

在您的示例中,您应该将my_list = []声明移至init函数...

class A:
    string = ""

    def __init__(self):
        self.my_list = []

    def add(self, data):
        self.string += "a"
        self.my_list.append(data)
    def print_list(self):
        print(self.string)
        print(self.my_list)

a = A()
b = A()
a.add("test")
a.print_list()
b.print_list()

希望得到这个帮助。

此致