假设我有一个这样的类:
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
部分我怎么能做到呢?
你不能直接使数据类中的属性只读。数据类被设计用来简化数据的存储,默认情况下,它们使所有字段都可读和可写。
但是,有几种方法可以实现你想要的结果,而无需使用
@stuff.setter
:
1. 使用
InitVar
和后期初始化:
from dataclasses import dataclass, InitVar
@dataclass
class DC:
stuff: InitVar[int]
_stuff: int = field(init=False)
def __post_init__(self, stuff: int):
self._stuff = stuff
在这个方法中,
stuff
作为初始化变量 (
InitVar
) 传递。 它不会直接成为类的属性,而是在
__post_init__
方法中使用它来初始化私有属性
_stuff
。 这使
_stuff
在初始化后无法修改。
2. 使用只读属性和不同的属性名:
from dataclasses import dataclass, field
@dataclass
class DC:
_stuff: int = field(repr=False)
@property
def stuff(self) -> int:
return self._stuff
此方法使用不同的属性名 (
_stuff
) 存储值,并使用只读属性 (
stuff
) 来访问它。
3. 使用第三方库:
一些第三方库,例如
attrs
和
pydantic
,提供了更强大的功能来定义只读属性和其他数据验证功能。
例如,使用
attrs
:
import attr
@attr.s(auto_attribs=True)
class DC:
_stuff: int = attr.ib(init=False)
@property
def stuff(self) -> int:
return self._stuff
@stuff.setter
def stuff(self, value: int):
# 可以在这里添加验证逻辑
self._stuff = value
选择哪种方法取决于你的具体需求和偏好。
如果只需要简单的只读属性,第一种或第二种方法就足够了。 如果你需要更强大的验证或其他功能,那么
attrs
或
pydantic
等第三方库可能是更好的选择。