python 修改冻结的数据类

python modifying frozen dataclass

我有一个 python 数据类,我不打算修改其属性。 但是,正如我刚刚意识到的那样,当我设置 frozen=True 时,它仍然可以通过 __dict__ 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 中的底层属性。语言的真正意图并不是阻止“想要”更改属性的人修改它(请注意 'private' 和 'protected' 语言中的属性,如 C++ 和 JAVA 可以 被一个打算通过使用自反 API 或通过名称修改来改变的人改变。

换句话说,在 严重的 系统中,没有任何情况可以通过访问系统代码或 classes 来修改属性应该是“危险的” " 并且禁止开发人员在同一进程中编写将 运行 的代码。如果你有这样的设计思路,你最好重新考虑一下,更有可能将“只读”数据放在一个单独的服务中,通过 API 或其他 RPC 方法访问,这样潜在的“恶意编码者”就不会正在处理 访问您的变量。

综上所述,有一些方法可以冻结可能会阻止 __dict__ 方法 - 其中之一是创建一个特殊的描述符,在对实例进行特定更改后将锁定写入:分配给 class 中的描述符的属性不会通过 __dict__。但如上所述,任何 打算 更改属性的人都可以转到描述符将属性保存在其中的任何存储(它必须在特定位置),或者简单地反转指示的更改从某一点开始,该值应为 read-only。

我试了一下,想出了这样一个描述符的示例代码,但它真的非常愚蠢——因为它在某些时候必须使用“绕过自己的方式”来标记 class 已锁定。但是,如您所述,使用 __slots__ 将使用冻结数据 class 并且不会具有可变 __dict__ - 另一方面,通过以下方式更改实例属性仍然微不足道class 属性的 .__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