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
我有一个 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