【问题标题】:python frozen dataclass immutable with object.__setattr__python 冻结的数据类与 object.__setattr__ 不可变
【发布时间】:2020-09-09 19:06:04
【问题描述】:

在遇到数据类之前,我将命名元组用于不可变数据结构,在我的用例中我更喜欢使用它(与问题无关)。

现在我了解到它们不是一成不变的!至少严格来说不是。

setattr(frozen_dc_obj, "prop", "value") 引发异常。好的。
但是为什么object.__setattr__(frozen_dc_obj,..) 有效呢?

与引发异常的namedtuple 相比!

from collections import namedtuple
from dataclasses import dataclass


NTTest = namedtuple("NTTest", "id")

nttest = NTTest(1)
setattr(nttest, "id", 2)  # Exception
object.__setattr__(nttest, "id", 2)  # Exception


@dataclass(frozen=True)
class DCTest:
    id: int

dctest = DCTest(1)
setattr(dctest, "id", 2)  # Exception
object.__setattr__(dctest, "id", 2)  # WORKS

【问题讨论】:

    标签: python python-3.x immutability namedtuple python-dataclasses


    【解决方案1】:

    namedtuple 定义了__slots__ = (),因此您不能设置任何属性(它没有__dict__)。

    另一方面,Frozen dataclasses 在他们的 __setattr__ 方法中执行手动检查,如果它是冻结的实例则引发异常。

    比较以下:

    >>> class Foo:
    ...     __slots__ = ()
    ... 
    >>> f = Foo()
    >>> f.__dict__  # doesn't exist, so object.__setattr__ won't work
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Foo' object has no attribute '__dict__'
    >>> @dataclass(frozen=True)
    ... class Bar:
    ...     pass
    ... 
    >>> b = Bar()
    >>> b.__dict__  # this exists, so object.__setattr__ works
    {}
    

    【讨论】:

      【解决方案2】:

      python Discord 频道上的其他人提供了另一个很棒的见解:

      冻结的数据类可能通过其自己的 setattr 限制访问,您可以通过将其传递给对象来绕过它。

      Namedtuples 派生自实际的元组,而不是 Python 中的实现,因此它们可以“真正”不可变,但如果您要绕过接口,如果数据类(同样可以在更混乱的方式)。 我建议使用 NamedTuple 输入命名元组,因为它提供了一个适当的类的可读性,但如果你需要数据类,那么冻结一个应该没问题。 NamedTuple 并不是真正的类型提示,而是像数据类一样在类定义中使用它们,并且与类类型构造函数相比,它的定义更简洁。

      我认为没有办法限制纯 python 中的所有访问,因为您可以调用对象的有效方法。

      在元组上赋值将涉及在 C 级别与 (c)python 交互,但在某种意义上它不是预期的接口是相同的。

      Python 总体上在安全性方面并没有那么大,如果不应该做的事情是用户的问题,如果他们这样做了。

      【讨论】:

        猜你喜欢
        • 2017-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-18
        • 1970-01-01
        • 2015-04-27
        • 1970-01-01
        • 2017-12-04
        相关资源
        最近更新 更多