在 python 数据类中使用 属性 getter 而没有 setter 的 pythonic 方法是什么?

What is a pythonic way to have property getters without setters with python dataclasses?

我有一种情况需要将变量 a、b 和 c 一起存储在一个数据类中,其中 c = f(a,b) 和 a、b 可以改变。我需要在打印对象时 c 与 a 和 b 一起显示,并且 c 不能更改,除非通过更改 ab。 我觉得最好的方法是让 c 成为一个用 属性.

创建的值

我尝试使用的最小示例:

@dataclass
class Demo:
    a:int
    b:int
    c:int = field(init=False)

    @property
    def c(self) -> int:
        return self.a * self.b

但是,调用此方法会导致 AttributeError: can't set attribute。我怀疑代码试图将 c 设置为 field(init=False),但失败了,因为 c 没有 setter.

我考虑过的选项(不包括我尝试过的导致代码以不同方式崩溃的替代方案):

尾注:

    @c.setter
    def c(self, val):
        caller = sys._getframe().f_back.f_code.co_name
        if caller != '__init__':
            raise ValueError # or some other error

如果您希望 c 成为计算的 属性,则完全删除 c 字段,只保留 属性:

@dataclass
class Demo:
    a:int
    b:int

    @property
    def c(self) -> int:
        return self.a * self.b

字段用于存储数据,c 不应该。

如果你想让c出现在repr中,你必须自己写__repr__方法。如果以后的代码需要 c 出现在 fields 中,那么您可能需要在更深层次上重新编写代码,并可能切换到 dataclasses.

以外的代码。

您的方法 c 覆盖了您的字段 c -- 原始 field 声明丢失,包括 init=False.

尝试更改顺序并使用 default= 参数。

from dataclasses import dataclass, field


@dataclass
class Demo:
    @property
    def c(self) -> int:
        return self.a * self.b

    a: int
    b: int
    c: int = field(init=False, default=c)


d = Demo(5, 10)
print(d)
d.a = 10
print(d)
d.c = 4  # generates an AttributeError

来自 Python 3.8.0 的输出:

Demo(a=5, b=10, c=50)
Demo(a=10, b=10, c=100)
Traceback (most recent call last):
...
  File "/home/rob/src/plot/dc.py", line 20, in <module>
    d.c = 4  # generates an AttributeError
AttributeError: can't set attribute