如何在 python 中构建冻结 class 的循环引用实例

How to construct circular referencing instances of a frozen class in python

我有一个相互引用的数据class实例。

from dataclasses import dataclass

@dataclass()
class Foo:
    id: int
    neighbor: 'Foo'
        
foo = Foo(1, None)
bar = Foo(2, foo)
foo.neighbor = bar

我真的想要一个冻结的 class,因为不能在多线程中操作这些对象 运行。但是如果我声明 frozen=True,最后一行显然会引发错误。我想不出如何处理这个问题。我阅读了 但解决方案对我不起作用,因为 foo.neighbor 应该指向另一个冻结的实例。

有什么办法可以实现吗?我不受 dataclasses 的约束。但是我在使用 namedtuples 时遇到了同样的问题。

frozen 通过覆盖 __setattr__ 来工作。您可以通过直接访问实例的 __dict__ 属性来完全绕过 __setattr__

foo.__dict__['neighbor'] = bar

我不知道这是否会产生任何意想不到的副作用(如果您使用 __slots__ 来防止创建 __dict__ 肯定不会起作用),但它可能足以满足您的用例。

(如果实现更改为使用 C 扩展而不是当前动态生成源代码以传递给 exec 的方法,这在 dataclass 的未来版本中也可能会失败。namedtuple 沿着这些路线发展,我相信。)


或者,您可以使用 dataclasses 本身用来初始化冻结 class 属性的相同技巧:显式使用 object.__setattr__

object.__setattr__(foo, 'neighbor', bar)