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

11 投票
3 回答
25325 浏览
提问于 2025-04-15 20:40

从父类继承一个类属性,然后在子类中改变这个属性的值是没问题的:

class Unit(object):
    value = 10

class Archer(Unit):
    pass

print Unit.value
print Archer.value

Archer.value = 5

print Unit.value
print Archer.value

输出结果是:
10
10
10
5
这没问题:弓箭手(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

输出结果是:
10
10
5
5

有没有办法在从父类继承列表时进行“深拷贝”?

非常感谢
Sano

3 个回答

1

你可以在弓箭手的定义里复制这个列表:

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

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

输出:

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

你还可以扩展这个想法,自动查找并复制在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
18

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

在第一个例子中,Unit.valueArcher.value 是两个变量,它们指向同一个值。当你执行 Archer.value = 5 时,你实际上是给 Archer.value 赋了一个新的值。

要解决你的问题,你需要给 Archer.list 赋一个新的列表值。

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

撰写回答