如何使数据类中的属性只读?

Cle*_*leb 6 python python-3.x python-dataclasses

假设我有一个这样的课程:

class C:

    def __init__(self, stuff: int):
        self._stuff = stuff

    @property
    def stuff(self) -> int:
        return self._stuff
Run Code Online (Sandbox Code Playgroud)

然后stuff是只读的:

c = C(stuff=10)
print(c.stuff)  # prints 10
Run Code Online (Sandbox Code Playgroud)

c.stuff = 2
Run Code Online (Sandbox Code Playgroud)

按预期失败

属性错误:无法设置属性

如何使用数据类获得相同的行为?如果我也想拥有一个setter,我可以这样做:

@dataclass
class DC:
    stuff: int
    _stuff: int = field(init=False, repr=False)

    @property
    def stuff(self) -> int:
        return self._stuff

    @stuff.setter
    def stuff(self, stuff: int):
        self._stuff = stuff
Run Code Online (Sandbox Code Playgroud)

但是没有这个@stuff.setter部分我怎么能做到呢?

小智 8

from dataclasses import dataclass

@dataclass(frozen=True)
class YourClass:
    """class definition"""
Run Code Online (Sandbox Code Playgroud)

https://docs.python.org/3/library/dataclasses.html#frozen-instances

类实例化后,当尝试更改其任何属性时,会引发异常。

  • 谢谢,但这会冻结所有属性,但我只想冻结某些属性,而不是全部...... (18认同)

jua*_*aga 1

因为在类定义中使用装饰器本质上会触发@dataclass装饰器使用属性对象作为默认字段,所以效果并不好。您可以在外部设置属性,例如:

>>> from dataclasses import dataclass, field
>>> @dataclass
... class DC:
...     _stuff: int = field(repr=False)
...     stuff: int = field(init=False)
...
>>> DC.stuff = property(lambda self: self._stuff) # dataclass decorator cant see this
>>> dc = DC(42)
>>> dc
DC(stuff=42)
>>> dc.stuff
42
>>> dc.stuff = 99
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
Run Code Online (Sandbox Code Playgroud)

  • 使用这种方法会产生丑陋的“repr”,并且正如 @Cleb 指出的那样,也会使“init”变得丑陋。真的很不幸,他们在“dataclasses.field”中没有“frozen”,这真的没有意义。 (3认同)
  • @Cleb,如果设置过一次,您可以使用一些标志来实现设置器,然后不允许进一步设置,但是,是的,它开始失去便利因素。 (2认同)