Python:不同的类实例成员被覆盖了吗?

时间:2019-12-04 09:03:12

标签: python-3.x python-2.7

似乎没有显式初始化,同一类的不同实例的列表和哈希将获得相同的内存地址。它是否正确?

#!/usr/bin/env python3

class DataManager:
    def __init__(self, name=[], value={}):
            self.parm_name = name
            self.parm_value = value
            pass

    def add_param(self, name, value):
            self.parm_name.append(name)
            self.parm_value[name] = float(value)

if __name__ == "__main__":
    dm1 = DataManager()
    dm2 = DataManager()
    print("Address of dm1: %s" % hex(id(dm1)))
    print("Address of dm2: %s" % hex(id(dm2)))
    print("Address of dm1.parm_name: %s" % hex(id(dm1.parm_name)))
    print("Address of dm2.parm_name: %s" % hex(id(dm2.parm_name)))

    dm1.parm_name.append("a")
    dm2.parm_name.append("b")

    print("dm1.parm_name: " + str(dm1.parm_name))
    print("dm2.parm_name: " + str(dm2.parm_name))

下面是执行结果:

Address of dm1: 0x7f20d9167f28
Address of dm2: 0x7f20d9167f98
Address of dm1.parm_name: 0x7f20d914bb08
Address of dm2.parm_name: 0x7f20d914bb08
dm1.parm_name: ['a', 'b']
dm2.parm_name: ['a', 'b']

dm1.parm_name的地址与dm2的地址对我来说真的很奇怪。并追加实际添加到同一列表。

如果我如下更改dm1和dm2定义,它将按预期工作:

dm1 = DataManager([], {})
dm2 = DataManager([], {})

很奇怪,不是吗? 谁能告诉我为什么?非常感谢〜

我也在Python2中尝试过,结果相同。以下版本:

$ python3 --version
Python 3.5.0
$ python2 --version
Python 2.7.5

2 个答案:

答案 0 :(得分:2)

代码中的默认参数

def __init__(self, name=[], value={})

mutable object

默认参数用于启用用于调用函数的可选参数,如果未将任何参数传递给__init__,则使用默认值,在这种情况下,将分配给class fields

如果默认值是mutable objects,则不会在每次调用时刷新它们, python一次又一次地使用相同的dictlist对象作为默认参数,并且不会为每次对dict的调用创建新的list__init__对象。最好将non mutable对象用作默认参数。

答案 1 :(得分:1)

查看代码的简化版本

class DataManager:
    def __init__(self, name=[]):
        self.parm_name = name

    def add_param(self, name):
        self.parm_name.append(name)


if __name__ == "__main__":
    dm1 = DataManager()
    dm2 = DataManager()

    dm1.add_param('a')
    dm2.add_param('b')

    print(dm1.parm_name)
    print(dm2.parm_name)

相对于稍作修改的版本:

class DataManager:
    def __init__(self, name=None):
        self.parm_name = [] if name is None else name

    def add_param(self, name):
        self.parm_name.append(name)


if __name__ == "__main__":
    dm1 = DataManager()
    dm2 = DataManager()

    dm1.add_param('a')
    dm2.add_param('b')

    print(dm1.parm_name)
    print(dm2.parm_name)

在以前的版本中,dm1.parm_name is dm2.parm_name返回True。