如何使用装饰器来修改可变类变量?

时间:2013-03-07 06:08:36

标签: python inheritance decorator

我有以下代码:

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应该有{{1但是X.items和Z.items都应该有items = [1]。这是我创建的装饰函数定义,它应该实现这个目标:

items = []

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

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

1 个答案:

答案 0 :(得分:2)

问题不在于装饰者。您对items属性的存储位置/方式存在误解。 YZ没有自己的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设置为空列表。这实际上设置了它操作的特定类的属性,而不是任何子类或超类。现在,当您访问它时,它将按预期工作。