dictproxy的目的是什么?

HYR*_*YRY 20 python cython

__dict__一种类型是一个dictproxy被只读对象.我想知道它的目的是什么.它仅适用于"不允许修改内置类型"吗?我发现了一种可以绕过它的方法.我知道修改内置类型并不是一个好主意.但我试图cdef class在飞行中修改Cython.

我想知道是否有任何危险的修改__dict__cdef class这种方式?

这是代码:

import gc
gc.get_referents(float.__dict__)[0]["square"] = lambda self: self*self
(3.14).square()
Run Code Online (Sandbox Code Playgroud)

Sco*_*t H 16

dictproxy(在类中找到)的目的是允许Python解释器中的优化并确保其稳定性.有关优化要求的详细信息,请参阅下面的MartijnPieters注释,这显然依赖于class.__dict__始终为字符串的键.

dictproxy似乎也起到了防止翻译中某些不稳定性的作用.有关这种不稳定性的更多信息,请参阅python.org上讨论的错误报告和错误修复,标题为Bypassing __dict__ readonlyness.如果你不使用某种代理机制,那么__dict__可以写入.如果可以写入,则可以删除.在bug报告中,他们讨论了__dict__可能被删除并导致解释器崩溃的一些场景.

请注意,这与类实例形成对比,您可以直接或通过__setitem__()以下方式分配:

  • instance.__dict__['x'] = 1

此外,__dict__ 可以删除实例.如果将其删除,则在尝试进行属性分配时会自动重新创建:

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

结论

总而言之,dictproxy允许类更优化地运行并使解释器更稳定.

  • `dictproxy`用于确保`class .__ dict__`中的键始终是字符串,允许Python解释器中的许多优化.代理阻止写入`class .__ dict__`,因此只能使用`setattr()`,而`class .__ setattr__`实现强制执行key-must-be-strings限制. (3认同)

Per*_*ijn 6

__dict__ 是一个包含类属性的名称空间对象.

只要不修改__dict__自身,修改dict对象就不会有问题:

例:

//good
MyClass.x = 1 

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

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

//also good
m.__dict__['x'] = 1
Run Code Online (Sandbox Code Playgroud)

Python文档[ LINK ]: Attribute assignment updates the module’s namespace dictionary, e.g., m.x = 1 is equivalent to m.__dict__["x"] = 1.

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

此外:

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

__dict__ | The namespace supporting arbitrary function attributes. | Writable

注意

它可能是Cpython有一个比pyhton略有不同的实现,但我可以从文档中读到它没有提到.

  • 您提供的示例是关于模块的命名空间,而不是类或实例的命名空间.你可以分配一个类属性(`Klass.x = 1`),它确实将它放入类的`__dict__`中,但你不能直接使用项目赋值(`Klass .__ dict __ ['x'] = 1`获取`TypeError:'dictproxy'对象不支持项目赋值`).但是,您可以在实例上使用项目赋值,假设该类没有特殊的逻辑来禁止它:`inst = Klass(); inst .__ dict __ ['x'] = 1`.所以你可以修改`dictproxy`,但不能直接修改它,因此称它为代理. (2认同)