Python 子类化 - 如何更新另一个类属性使用的类属性

标签 python inheritance attributes subclass wtforms

假设有一个类属性是根据另一个类属性计算的:

class ClassA(object):
    attr1=5
    attr2=attr1+10

>>ClassA.attr2
15

然后在子类中,我想更新第一个类属性以导致第二个类属性发生更改,而不重新定义第二个类属性。例如:

class ClassB(ClassA):
    attr1=10

我希望发生的是:

>>ClassB.attr2
20

然而,情况并非如此,因为 attr2 是在重新定义 attr1 之前计算的。有没有办法在不重新定义第二个属性的情况下获得这种行为?

(我的特定用例是使用从 Form 类属性派生的 Field 属性(格式、选择等)定义 WTForms,因此我可以对基本 Form 进行子类化并更改这些属性,而无需重新定义整个 Field .)

最佳答案

没有办法直接执行此操作。

对于实例属性,而不是类属性,您可以使用 @property 轻松模拟它。要么在每次请求时即时计算 attr2:

class Spam:
    def __init__(self, a):
        self.a = a
    @property
    def twoa(self):
        return 2*self.a

(如果计算成本较高,可能会添加缓存),或者每当有人修改 attr1 时重新计算 attr2:

class Spam:
    def __init__(self, a):
        self.a = a
    @property
    def a(self):
        return self._a
    @a.setter
    def a(self):
        self._a = a
        self.twoa = 2*a
<小时/>

这只有效,因为 property 创建了一个存储在类对象中的描述符,而不是实例,因此当有人查找 twoa 时(在第一个示例中)或 a(在第二个中)在 Spam 实例上,它会回退到查找类上的描述符。

如果您想要类属性的第一个属性,则在查找实例上的值时它会按原样工作,但不会在类本身上查找值(不幸的是,这正是您在示例中所做的事情)。

如果您需要第二个,它根本不起作用。

例如:

>>> class Spam:
...     a = 10
...     @property
...     def twoa(self):
...         return 2*self.a
>>> spam = Spam()
>>> spam.twoa
20
>>> Spam.twoa
<property at 0x12345678>
>>> class Eggs(Spam):
...     a = 5
>>> eggs = Eggs()
>>> eggs.twoa
10
>>> Eggs.twoa
<property at 0x12345678>

如果这不是问题,那就太好了。但如果是,您需要将描述符放在类的类上,即元类:

class MetaSpam(type):
    @property
    def twoa(cls):
        return 2 * cls.a

class Spam(metaclass=MetaSpam):
    a = 2

class Eggs(Spam):
    a = 3

对于像 twoa (或您的 attr2)这样的简单情况,拖入元类是可怕的过度杀伤力。

但是对于您很可能已经拖入自定义元类的情况(例如复杂的表单和字段系统),这可能是合适的。

关于Python 子类化 - 如何更新另一个类属性使用的类属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51739255/

相关文章:

python - 如何在python中将数据放在不同的行上

python - 读取文本文件的每一行并确定它是否还有另一个字母

c++ - 在自动函数中放置 gcc 函数属性的位置

java - 为什么我的继承申请不起作用?

java - 父类(super class)子类实例化

asp.net - 创建一个操作过滤器属性,绕过操作的实际执行并为其返回一个值

java - 如何在我自己的API中实现Dicom属性字典

python - 通过 SFTP 从远程服务器读取 GZIP 文本文件

python - 如何在 scikit-learn 中进行预处理后保留数据帧的列标题

Python 动态继承 : How to choose base class upon instance creation?