dictproxy的目的是什么?

25 投票
2 回答
14847 浏览
提问于 2025-04-18 18:09

一个类型的 __dict__ 是一个只读的 dictproxy 对象。我想知道它的目的是什么。难道只是为了“禁止修改内置类型”吗?我发现有一种方法可以绕过这个限制。我知道修改内置类型不是个好主意,但我正在尝试动态修改 Cython 的 cdef class

我想知道以这种方式修改 cdef class__dict__ 是否有危险?

这里是代码:

import gc
gc.get_referents(float.__dict__)[0]["square"] = lambda self: self*self
(3.14).square()

2 个回答

7

__dict__ 是一个命名空间对象,用来存放类的属性。

只要你不修改 __dict__ 本身,修改这个字典对象应该没有问题

举个例子:

//good
MyClass.x = 1 

//bad
MyClass.__dict__['x'] = 1

//good
m = MyClass()
m.x = 1

//also good
m.__dict__['x'] = 1

根据Python的文档 [ 链接 ]:

给属性赋值会更新模块的命名空间字典,比如,m.x = 1 相当于 m.__dict__["x"] = 1。

所以,修改 dict 的对象应该没有问题。

此外:

因为我们可以修改类的属性,所以类的字典总是可以写的:

__dict__ | 支持任意函数属性的命名空间。 | 可写

注意

可能CPython的实现和Python有些不同,但根据我从文档中看到的,并没有提到这一点。

19

dictproxy的主要作用是在类中使用,它可以帮助Python解释器进行一些优化,并确保其稳定性。具体的优化要求可以参考MartijnPieters的评论,主要是因为类的属性名(即class.__dict__中的键)必须始终是字符串。

dictproxy还可以防止解释器出现某些不稳定的情况。关于这种不稳定性,可以查看python.org上讨论的一个错误报告和修复,标题是绕过 __dict__ 的只读性。如果不使用某种代理机制,__dict__是可以被写入的。如果可以写入,就可以被删除。在这个错误报告中,他们讨论了一些情况下__dict__被删除后导致解释器崩溃的情况。

需要注意的是,这和类的实例是不同的,类的实例是可以直接赋值的,或者使用__setitem__()来赋值:

  • instance.__dict__['x'] = 1

另外,实例的__dict__也是可以被删除的。如果被删除了,当你尝试给属性赋值时,它会自动重新创建:

del instance.__dict__
instance.a = 1
instance.__dict__

总结

总的来说,dictproxy让类的操作更加高效,同时也让解释器更加稳定。

撰写回答