首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Monkeypatching函数命名空间

Monkeypatching函数命名空间
EN

Stack Overflow用户
提问于 2018-05-23 00:19:26
回答 2查看 109关注 0票数 4

"Define @property on function"的启发,我试图重写函数的命名空间:

代码语言:javascript
复制
>>> class MyDict(dict):
...     def __getitem__(self, item):
...         if item == 'k2':
...             return 'v2'
...         return super().__getitem__(item)
...     
>>> def f():
...     pass
... 
... 
>>> f.__dict__ = MyDict({'k1': 'v1'})
>>> 
>>> f.k1
'v1'
>>> f.k2
AttributeError: 'function' object has no attribute 'k2'

为什么f.k1可以解决问题,而f.k2不能解决呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-23 00:56:00

简短的版本:因为CPython的PyDict_GetItem函数不是子类友好的(这并不是要明确的;PyDict_*函数都是专门针对PyDict_Object本身的,而不是通用映射)。

长版本:检索属性将调用PyObject_GetAttr。对于没有显式定义自定义tp_getattrotp_getattr (和 does not)的类,这将导致PyObject_GenericGetAttr。假设在类本身上没有发现任何东西,PyObject_GenericGetAttr (嗯,实现它的私有API函数) to retrieve the valuePyDict_GetItem显式地使用dict的C级内部来执行访问,绕过您可能定义的任何自定义__getitem__,因此您的自定义__getitem__永远不会被调用;从所有实际目的来看,dict子类只是一个dict

我最初希望您能够通过 hook实现这个特定案例的工作,但事实证明,只有在调用了等效的__getitem__ (dict_subscript)时,才会调用这种情况,而不是通过C级的直接访问API(如PyDict_GetItem (根本不通过dict_subscript ))。

基本上,在这里,CPython似乎做出了优先考虑性能而不是完全灵活性的选择。任何用作dict__dict__子类都会被访问,就好像它是一个普通的dict (如果子类做了一些魔术来存储一个值,而假装存储了一个不同的值,因为魔术被绕过了),那么这个子类可能会变得有点奇怪,并且所有不是dict子类的映射在赋值时都会被拒绝(当您试图将它们分配给f.__dict__时,您会得到一个TypeError )。

票数 5
EN

Stack Overflow用户

发布于 2018-05-23 00:55:20

__getitem__文档中的第一句是:“调用以实现自键的评估”。您假设(希望) f.k1的计算值执行显式操作f.__dict__["k1"],但它不执行。如果您在__getitem__的第一行中放置了一个print语句,您将看到代码从未调用该函数。

我不知道这是为什么,但我怀疑这是出于性能原因。无论如何,我想不出一个很好的用例来替换函数的__dict__。有太多的方法可能会失败。

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50478162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档