我有一个 python 数据类,我不打算修改其属性。 然而,正如我刚刚意识到的,当我设置
__dict__
时,它仍然可以通过 frozen=True
even进行修改。例如:
@dataclass(frozen=True)
class C:
a: int = 1
c = C()
c.a = 2 # dataclasses.FrozenInstanceError: cannot assign to field 'a'
c.__dict__['a'] = 2 # legit
print(c)
# C(a=2)
我知道这是属于底层的
__dict__
attr 是一个可变对象,并且在 __setattr__
处引发错误并不能真正涵盖。
另一方面,我确实需要以集体方式访问所有属性。此类任务的最佳实践是什么?我要复印
__dict__
吗?或者也许 slots=True
会是一个潜在的候选人?
提前致谢。
正如您所意识到的,人们必须“好”地不遗余力地修改这些属性之一。 虽然可能比直接访问实例的
__dict__
来修改属性要困难一些,但由于 Python 的动态和自反性质,人们“总是”可以更改 Python 中的底层属性。语言。该语言的真正目的并不是阻止“想要”更改属性的人修改它(请注意,像 C++ 和 Java 这样的语言中的“私有”和“受保护”属性也可以通过以下方式更改:打算通过使用自反 API 或通过名称修改来做到这一点)。
换句话说,在一个“严重”的系统中,通过访问系统代码或类来修改属性的情况不应该是“危险的”,并且对于编写将在同一进程中运行的代码的开发人员来说应该是“危险的”。如果你有这样的设计思维,你最好重新考虑一下,更有可能将“只读”数据放在一个单独的服务中,通过 API 或其他 RPC 方法访问,这样潜在的“恶意编码者”就不会在进程中 访问您的变量。 总而言之,有一些方法可以冻结属性,这可能会阻止__dict__
方法 - 其中之一是创建一个特殊的描述符,在实例上进行特定更改后将锁定写入:分配给描述符的属性课程不会通过__dict__
。但如上所述,任何想要更改属性的人都可以转到描述符保存属性的任何存储(它必须位于某个位置),或者简单地反转指示该值应该是只读的更改某个点。
我尝试了一下,并为这样的描述符想出了示例代码,但它真的非常愚蠢 - 因为它在某些时候必须使用“规避自身的方法”才能将类标记为锁定。但是,如您所描述的那样使用 __slots__
__dict__
- 另一方面,通过类属性的
.__set__
方法来更改实例属性仍然很简单:
In [124]: @dataclass(frozen=True)
...: class A:
...: __slots__=("a",)
...: a: int
...:
In [125]: a = A(42)
In [126]: a.a = 23
FrozenInstanceError ...
In [127]: a.__dict__
...
AttributeError: 'A' object has no attribute '__dict__'
In [128]: A.a.__set__(a, 23)
In [139]: a.a
Out[139]: 23