【问题标题】:Python: Inheritance of a class attribute (list)Python:类属性的继承(列表)
【发布时间】:2011-01-30 02:32:48
【问题描述】:

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

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 的值,但是当我更改 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

从超类继承列表时,有没有办法“深拷贝”列表?

非常感谢
佐野

【问题讨论】:

    标签: python inheritance list deep-copy class-attributes


    【解决方案1】:

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

    第一种情况Unit.valueArcher.value 是引用相同值的两个变量。当您执行 Archer.value = 5 时,您正在为 Acher.value 分配一个新的引用。

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

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

    【讨论】:

    • 感谢您的回答。我的问题是我想要两者的优点:我想向 Unit 添加新属性,然后 Archer 也应该获得这些属性,但是当更改 Archer 新继承的属性的值时,Unit 的属性(或 Unit 的其他后代)是保持不变。另一方面,如果我决定再次从 Unit 中删除该属性,Archer 也应该失去它。如果创建了新变量,它当然不会。 -_-° 我的逻辑错误。
    【解决方案2】:

    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
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-02
        • 2012-07-25
        • 2016-11-11
        • 1970-01-01
        • 1970-01-01
        • 2015-03-27
        相关资源
        最近更新 更多