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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2488306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-04 00:45:47  来源:igfitidea点击:

Python: Inheritance of a class attribute (list)

pythoninheritancelistdeep-copyclass-attributes

提问by Sano98

inheriting a class attribute from a super class and later changing the value for the subclass works fine:

从超类继承类属性,然后更改子类的值工作正常:

class Unit(object):
    value = 10

class Archer(Unit):
    pass

print Unit.value
print Archer.value

Archer.value = 5

print Unit.value
print Archer.value

leads to the output:
10
10
10
5
which is just fine: Archer inherits the value from Unit, but when I change Archer's value, Unit's value remains untouched.

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

Now, if the inherited value is a list, the shallow copy effect strikes and the value of the superclass is also affected:

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

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

Output:
10
10
5
5

输出:
10
10
5
5

Is there a way to "deep copy" a list when inheriting it from the super class?

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

Many thanks
Sano

非常感谢
佐野

回答by mikerobi

It is not a matter of shallow or deep copies, it is a matter of references and assignments.

这不是浅拷贝或深拷贝的问题,而是引用和赋值的问题。

It the first case Unit.valueand Archer.valueare two variables which reference the same value. When you do Archer.value = 5, you are assigning a new reference to Acher.value.

它是第一种情况,Unit.value并且Archer.value是引用相同值的两个变量。当您这样做时Archer.value = 5,您正在为 Acher.value 分配一个新的引用。

To solve your problem you need to assign a new list value to the Archer.list.

要解决您的问题,您需要为Archer.list.

If these values are only going to be accessed by class methods, then the simplest solution is to do the assignment when the class is initialized.

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

回答by John La Rooy

Michael's answer is nice and simple, but if you wish to avoid having to add that line to each Unit subclass - maybe you have a bunch of other lists like that one, a metaclass is an easy way to solve the problem

Michael 的回答很好也很简单,但是如果您希望避免将该行添加到每个 Unit 子类中 - 也许您有一堆其他类似的列表,元类是解决问题的简单方法

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

output:

输出:

[10]
[10]
[10]
[5]

You can also extend this same idea to automatically find and copy up lists (and dicts) defined in Unit

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

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

回答by Michael Williamson

You coud copy the list in the definition of Archer:

您可以复制 Archer 定义中的列表:

class Archer(Unit):
    listvalue = Unit.listvalue[:]