如何确保每个子类都获得其父类属性的新副本(在Python中)?

时间:2012-05-18 20:21:40

标签: python oop inheritance pass-by-reference mutable

我有一个基类,它有一个空白列表作为类属性。许多子类继承自此基类。目的是将此列表类属性与类方法结合使用,以允许每个子类跟踪其自己的实例的某组。每个类都应该有一个单独的列表,其中只包含自己的实例。

当我对这个继承方案做了一个简单的实现时,在调试过程中我注意到实际上每个子类都与一个类属性共享完全相同的列表,而且我再次对python传递列表这一事实感到好玩引用。仔细观察,似乎父类,方法和值等的每个类属性都只是通过引用传递给每个子节点,并且除非在子节点的定义中明确地重写了特定属性,否则这不会改变。 / p>

在创建子类时,重新初始化子类变量的最佳方法是什么?理想情况下,我想要一种方法来确保每个孩子都以cls.instances属性开头,该属性是一个唯一的空白列表,在任何子节点中都不包含额外的代码。否则,我首先要为继承而烦恼什么? (不要回答)

4 个答案:

答案 0 :(得分:3)

不要不尊重@DanielRoseman和他富有洞察力的回答,但我想我会写出你如何使用元类来完成我理解你想要完成的事情:

mc.py:

class Meta(type):
    def __init__(cls, name, bases, attrs):
        cls.foo = []

class A:
    __metaclass__ = Meta

class B(A):
    pass

鉴于此:

>>> import mc
>>> mc.A.foo
[]
>>> mc.A.foo.append(1)
>>> mc.A.foo
[1]
>>> mc.B.foo
[]

答案 1 :(得分:1)

这可能是您需要进入元类的重点。你所说的是,每次定义一个新的子类时,都需要一组新的变量。因此,元类是类类的类:每次定义子类时,都要实例化元类的新实例。每个元类实例都可以有自己的实例变量,这意味着每个子类都有自己的一组类变量。

关于如何使用元类在Marty Alchin's blog上执行此类操作有很好的说明。

答案 2 :(得分:0)

你的意思是这样的:

    >>> class Foo():
    ...   alist = []
    ...   def __init__(self):
    ...     pass
    >>> foo = Foo()
    >>> foo.alist
    []
    >>> Foo.alist
    []
    >>> Foo.alist.append(7)
    >>> Foo.alist
    [7]
    >>> foo.alist
    [7]
    >>> foo2 = Foo()
    >>> foo2.alist
    [7]

答案 3 :(得分:0)

我认为你在这里遇到的问题是类实际上是对象,而类成员是类的type类型对象的成员,而不是其实例的成员。从这个角度来看,很容易理解为什么子类实际上没有父类的类级成员的唯一实例。我过去用来解决这类问题的方法是让父级.instances类变量成为一个字典,然后在父级__init__方法中对每个子级的实例进行编目。存储在.instances字典中的self类型的密钥下的列表。请记住,即使在父作用域内,在type()上执行self也会为您提供直接创建对象的类型,而不是本地作用域的类型。