我有以下代码:
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的所有实例之间共享,但是,我不知道子类是否受到影响。也许这种行为只发生在可变属性上?
实现目标的正确方法是什么?
答案 0 :(得分: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
设置为空列表。这实际上设置了它操作的特定类的属性,而不是任何子类或超类。现在,当您访问它时,它将按预期工作。