1

我有以下代码:

class X(object):
    items = []

class Y(X):
    pass

class Z(X):
    pass

我正在尝试创建一个装饰器,它只会将一个对象添加到 Y 的“项目”列表中。所以下面的代码,

@addItems
class Y(X):
    pass

应该在 Y.items 上附加一些东西(例如,假设是整数 1),但不能修改 X.items、Z.items 或 X 的任何其他子类。基本上,Y.items 应该只有items = [1]X.items 和 Z .items 都应该有items = []. 这是我创建的应该实现该目标的装饰器函数定义:

def addItems(cls):
    cls.items.append(1)
    return cls

但这不起作用 - 当我使用装饰器时,它最终会修改 X 和 X 的所有其他子类的“项目”列表。什么给出了?我知道 Python 中的类属性在 X 的所有实例之间共享,但是,我不知道子类受到影响。也许这种行为只发生在可变属性上?

实现我的目标的正确方法是什么?

4

1 回答 1

2

问题不在于装饰器。items您对属性的存储 位置/方式有误解。Y并且Z没有自己的items属性。相反,只有一个items属性。您在 上定义了它X,如果您这样做Y.items(或Z.items),由于在子类上找不到该属性,因此会在超类上动态查找它。如果你这样做X.items is Y.items,你会看到它评估为 True --- 只有一个items列表。这意味着当您修改它时,所有类都会看到修改。

如果你想给每个类一个自己的items列表,你必须给每个类一个自己的items列表:

class X(object):
    items  = []

class Y(object):
    items  = []

class Z(object):
    items  = []

除非你告诉它,否则 Python 从不复制任何东西。仅仅因为您定义了一个从具有属性的类继承的子类,这并不意味着 Python 会为子类创建一个新的属性副本。它只是重复使用超类中的相同对象。

如果您想“神奇地”为每个类赋予其自己的 items 属性,您可以在装饰器中执行此操作:

def addItems(cls):
    cls.items = []
    cls.items.append(1)
    return cls

这首先将类设置items为一个空列表。这实际上是在它所操作的特定类上设置属性,而不是在任何子类或超类上。现在,当您访问它时,它将按您的预期工作。

于 2013-03-07T06:15:48.487 回答