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

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

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

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

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

最佳答案

问题不在于装饰器。您对 items 属性的存储位置/方式存在误解。 YZ 没有自己的 items 属性。相反,只有一个 items 属性。您在 X 上定义了它,如果您执行 Y.items (或 Z.items),因为在子类上找不到该属性,它是在父类(super class)上动态查找的。如果您执行X.items is Y.items,您将看到它的计算结果为True——只有一个items列表。这意味着当您修改它时,所有类都会看到修改。

如果您想为每个类提供自己的 items 列表,那么您必须为每个类提供自己的 items 列表:

class X(object):
    items  = []

class Y(object):
    items  = []

class Z(object):
    items  = []

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

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

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

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

关于python - 如何使用装饰器来修改可变类变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15264290/

相关文章:

php - 在 PHP 中构造装饰器

python - 添加逗号使 python 对象成为 Tuple

python - Cherrypy 使用 cxfreeze 打包时找不到 wsgiserver 模块

python - 如何在Python中正确下载股票数据

python - 修改包装函数中的函数代码

python - 如何使用 Python 装饰器处理 'self' 参数

python - 包含特定链接的有向无环图中的路径总数

java - @XmlSeeAlso 替代方案

c++ - 了解 C++ 中子类的类

java - spring数据中的多态查询