dictproxy的目的是什么?

25

__dict__是类型的一个dictproxy对象,只能读取。我想知道它的目的是什么。它只是用于“不允许修改内置类型”吗?我找到了一种方法来绕过这个限制。我知道修改内置类型不是一个好主意,但我正在尝试在运行时修改Cython的cdef class

我想知道这样修改cdef class__dict__是否存在任何危险?

下面是代码:

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

1
可能此链接此链接会有所帮助。 - Tanmaya Meher
@Job,这不是同一个问题,因为setattr不能用于内置类。我想要做的是修改Cython中cdef class__dict__ - HYRY
1
你的示例会修改同一进程中所有子解释器运行的“float”。并且,通过绕过“type_setattro”,它不会与PyTypeObject插槽进行同步特殊方法(update_slot)或清除方法缓存(PyType_Modified)。我不知道“cdef class”,但Python 3稳定的API有PyType_FromSpec,可以创建扩展堆类型,并可通过正常设置属性而不是黑客类字典来安全地进行修改。 - Eryk Sun
_tkinter.Tcl_Obj 是一个 Python 3 扩展类型的示例,它允许您设置属性。 - Eryk Sun
2个回答

19
中的dictproxy旨在优化Python解释器并确保其稳定性。参见MartijnPieters下面的评论,了解有关优化要求的详细信息,这些优化显然依赖于class.__dict__的键始终为字符串。

dictproxy还似乎在保护解释器免受某些不稳定性的影响方面发挥着作用。有关此类不稳定性的更多信息,请参见python.org上标题为Bypassing __dict__ readonlyness的错误报告和错误修复讨论。如果不使用某种代理机制,则可以对__dict__进行编写。如果它可以编写,那么它就可以被删除。在错误报告中,他们讨论了一些情况,其中__dict__可能被删除并导致解释器崩溃。

请注意,这与类实例形成对比,您可以直接或使用__setitem__()进行分配:

  • instance.__dict__['x'] = 1

此外,实例__dict__可以被删除。如果删除它,则尝试属性分配时会自动重新创建:

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

结论

因此,dictproxy使类的操作更加优化,并使解释器更加稳定。


3
dictproxy 用于确保 class.__dict__ 中的键始终为字符串,从而使 Python 解释器能够进行多种优化。该代理防止向 class.__dict__ 写入,因此只能使用 setattr(),并且 class.__setattr__ 实现了键必须是字符串的限制。 - Martijn Pieters

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始终是可写的:

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

注意

CPython可能与Python有稍微不同的实现,但是根据文档,它没有提到。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接