[英]How to make attribute in dataclass read-only?
假設我有一個像這樣的 class :
class C:
def __init__(self, stuff: int):
self._stuff = stuff
@property
def stuff(self) -> int:
return self._stuff
那么stuff
是只讀的:
c = C(stuff=10)
print(c.stuff) # prints 10
和
c.stuff = 2
按預期失敗
AttributeError:無法設置屬性
如何使用數據類獲得相同的行為? 如果我也想有一個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
但是如果沒有@stuff.setter
部分,我怎么能做到呢?
為了減少dataclass
提供的樣板文件,我發現唯一的方法是使用描述符。
In [236]: from dataclasses import dataclass, field
In [237]: class SetOnce:
...: def __init__(self):
...: self.block_set = False
...: def __set_name__(self, owner, attr):
...: self.owner = owner.__name__
...: self.attr = attr
...: def __get__(self, instance, owner):
...: return getattr(instance, f"_{self.attr}")
...: def __set__(self, instance, value):
...: if not self.block_set:
...: self.block_set = True
...: setattr(instance, f"_{self.attr}", value)
...: else:
...: raise AttributeError(f"{self.owner}.{self.attr} cannot be set.")
In [239]: @dataclass
...: class Foo:
...: bar:str = field(default=SetOnce())
In [240]: test = Foo("bar")
In [241]: test.bar
Out[241]: 'bar'
In [242]: test.bar = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-242-9cc7975cd08b> in <module>
----> 1 test.bar = 1
<ipython-input-237-bddce9441c9a> in __set__(self, instance, value)
12 self.value = value
13 else:
---> 14 raise AttributeError(f"{self.owner}.{self.attr} cannot be set.")
15
AttributeError: Foo.bar cannot be set.
In [243]: test
Out[247]: Foo(bar='bar')
因為在 class 定義中使用裝飾器本質上會觸發@dataclass
裝飾器以使用屬性 object 作為默認字段,所以效果不佳。 您可以在外部設置屬性,例如:
>>> 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
from dataclasses import dataclass
@dataclass(frozen=True)
class YourClass:
"""class definition"""
https://docs.python.org/3/library/dataclasses.html#frozen-instances
class 實例化后,當嘗試更改其任何屬性時,將引發異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.