Python:类属性的继承(列表)

San*_*o98 5 python inheritance list deep-copy class-attributes

继承超类的类属性,稍后更改子类的值可以正常工作:

class Unit(object):
    value = 10

class Archer(Unit):
    pass

print Unit.value
print Archer.value

Archer.value = 5

print Unit.value
print Archer.value
Run Code Online (Sandbox Code Playgroud)

导致输出:
10
10
10
5
这很好:Archer继承了Unit的值,但是当我改变Archer的值时,Unit的值保持不变.

现在,如果继承的值是列表,则浅拷贝效果会发生,并且超类的值也会受到影响:

class Unit(object):
    listvalue = [10]

class Archer(Unit):
    pass

print Unit.listvalue
print Archer.listvalue

Archer.listvalue[0] = 5

print Unit.listvalue
print Archer.listvalue
Run Code Online (Sandbox Code Playgroud)

产量:
10
10
5
5

从超类继承列表时,有没有办法"深度复制"列表?

非常感
谢佐诺

mik*_*obi 13

这不是浅层或深层复制的问题,而是引用和分配的问题.

它是第一种情况Unit.value,Archer.value是引用相同值的两个变量.执行此操作时Archer.value = 5,您将为Acher.value分配新引用.

要解决您的问题,您需要为其分配一个新的列表值Archer.list.

如果这些值只能通过类方法访问,那么最简单的解决方案是在初始化类时进行赋值.


Joh*_*ooy 7

迈克尔的答案很简单,但是如果你想避免将这一行添加到每个单元的子类中 - 也许你有一堆其他的列表,那么元类就是一种解决问题的简单方法

class UnitMeta(type):
    def __init__(self, *args):
        super(UnitMeta, self).__init__(*args)
        self.listvalue = [10]

class Unit(object):
    __metaclass__ = UnitMeta
    pass

class Archer(Unit):
    pass

print Unit.listvalue
print Archer.listvalue

Archer.listvalue[0] = 5

print Unit.listvalue
print Archer.listvalue
Run Code Online (Sandbox Code Playgroud)

输出:

[10]
[10]
[10]
[5]
Run Code Online (Sandbox Code Playgroud)

您还可以扩展同样的想法,以自动查找和复制Unit中定义的列表(和dicts)

class UnitMeta(type):
    def __init__(self, *args):
        super(UnitMeta, self).__init__(*args)
        for superclass in self.__mro__:
            for k,v in vars(superclass).items():
                if isinstance(v, (list, dict, )):
                    setattr(self, k, type(v)(v))

class Unit(object):
    __metaclass__ = UnitMeta
    listvalue = [10]

class Archer(Unit):
    pass
Run Code Online (Sandbox Code Playgroud)