Python修改冷冻数据类

发布于 2025-01-21 20:23:00 字数 611 浏览 1 评论 0原文

我有一个Python Dataclass,其属性我不打算修改。 但是,正如我刚刚意识到的那样,它仍然可以通过__ dict __ 甚至进行修改。例如:

@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 at at __ _______etattr __并没有真正覆盖的基础__ dict __ dict __ attr。

另一方面,我确实需要以集体方式访问所有属性。这种任务的最佳实践是什么?我是否制作__ dict __的副本?也许插槽= true可能是潜在的候选人?

提前致谢。

I have a python dataclass whose attributes I didn't intend to modify.
However, as I just realized, it is still modifiable via __dict__ even when I set frozen=True. For instance:

@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)

I understand that this is owning to the underlying __dict__ attr is a mutable object, and raising error at __setattr__ doesn't really cover.

On the other hand, I do have a need to access all the attributes in a collective manner. What is the best practice for this kind of task? Do I make a copy of __dict__? Or maybe slots=True would be a potential candidate?

thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

荒人说梦 2025-01-28 20:23:00

正如您所感知到的那样,必须避开 来修改这些属性之一。

虽然可以使访问实例的__ dict __直接访问属性更加困难,但人们将可以在python中更改基础属性。 ,由于语言的动态和反思性。确实不是“想要”“想要”更改属性修改它的语言的目的(请注意,在语言中,“私有”和“受保护”属性具有C ++和Java,Java和Java可以也。

换句话说,在A 严重系统中没有场景可以修改属性,通过一个可以访问系统代码或类的属性,应该是“危险的”,而对于开发人员来说,编写将在该代码中运行的代码的限制相同的过程。如果您有一些设计思考,那么您最好重新考虑,更有可能将“仅读取”数据放入单独的服务中,可以通过API或其他RPC方法访问,因此潜在的“恶意编码器”没有在过程中访问您的变量。

话虽如此,有一些方法可以冻结属性可能会阻止__ dict __方法 - 其中之一是创建一个特殊的描述符,在实例上进行一定的更改后会锁定写作:分配的属性对于班上的描述符,不会浏览__ dict __。但是如上所述,任何打算更改属性的任何人都可以转到描述符的任何存储器都保留属性(必须位于某个位置),或者简单地逆转指示该值的更改从某个点上读取。

我玩耍了,并提出了这样的描述符的示例代码,但这确实非常非常愚蠢 - 因为在某个时候,它必须使用“绕开自身的方式”以将类标记为锁定。但是,如您所描述的那样,使用__插槽__将与冷冻数据一起使用,并且不会具有可变的__ dict __ dict __ - 另一方面,通过进行更改实例属性仍然很容易通过类属性的.__设置__方法:

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

As you had perceived well, one has to go well out of his way to modify one of these attributes.

While it is possible to make it a bit more difficult than accessing the instance's __dict__ directly to modify an attribute, it will always be possible for one to change the underlying attribute in Python, due to the dynamic and reflexive nature of the language. It is really not the intent of the language to prevent one that "wants" to change an attribute from modifying it (note that 'private' and 'protected' attributes in languages that feature them like C++ and Java can also be altered by one intending to do so by using reflexive API's or going through the name mangling).

In other words there is no scenario in a serious system that modifying an attribute, by one having access to the system code or classes should be "dangerous" and off limits for developers writing code that will run in the same process. If you have some designing thinking so, you'd better rethink that, more likely putting the "read only" data in a separate service, accessible via API or other RPC method, so that potential "malicious coders" do not have in process access to your variable.

All that said, there are ways to freeze attributes that might prevent the __dict__ approach - one of which would be to create a special descriptor that after a certain change on the instance would lock writing: attributes that are assigned to a descriptor in the class won't go through __dict__. But as stated above, anyone intending to change the attribute can go to whichever storage the descriptor keeps the attribute in (it has to be in a certain place), or simply reverse the change that indicates the value should be read-only from a certain point on.

I played around, and came up with example code for such a descriptor, but it is really, really silly - as it at some point has to use the "way to circumvent itself" in order to mark the class as locked. However, using __slots__ as you described will work with a frozen dataclass and will not feature a mutable __dict__ - on the other hand, it still trivial to change the instance attribute by going through the class attribute's .__set__ method:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文