将__getitem__添加到模块

时间:2015-03-15 17:53:44

标签: python

所以这是一个非常简单的问题。如何将__getitem__添加到Python模块。我大多只是希望它易于使用,但令人困惑的是它为什么不让我“设置它”。以下是__getitem__半工作的简单示例,但我希望other['test']能够正常工作。

这里有完整的输出:

hello
hello
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    print other['test']
TypeError: 'module' object has no attribute '__getitem__'

main.py

import other
print other.get('test')
print other.__getitem__('test')
print other['test']

other.py

test = 'hello'

def __getitem__(name):
    return globals()[name]

get = __getitem__

我已尝试使用__getitem__设置globals()globals()['__getitem__'] = __getitem__。它没有用。我尝试在main.py中设置它。所以我很困惑为什么它坚持不允许我使用other['test']

如果不可能,那么一个简短的理由就是好的。

2 个答案:

答案 0 :(得分:5)

特殊方法是looked up on the type,而不是实例。 Python查找type(other).__getitem__(),但不可用。您必须将__getitem__方法添加到module类型;你不能用Python。

您必须将module中的整个sys.modules实例替换为您自己类的实例,以实现您想要的目标:

class MyModule(object):
    def __init__(self, namespace):
        self.__dict__.update(namespace)
    def __getitem__(name):
        return self.__dict__[name]

import other
import sys
sys.modules[other.__name__] = MyModule(other.__dict__)

答案 1 :(得分:3)

此限制不仅适用于模块,它适用于类型不是objectobject的某些子类的任何内容,或具有从不与{object结束的元类的内容。 1 {} mro

例如,您还可以使用type类型

来查看此情况
In [32]: class Foo(type):
   ....:     pass
   ....: 

In [33]: type(Foo)
Out[33]: type

In [34]: Foo.__getitem__ = lambda x, y: x.__dict__.get(y)

In [35]: Foo.foo = "hello"

In [36]: Foo['foo']
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-38-e354ca231ddc> in <module>()
----> 1 Foo['foo']

TypeError: 'type' object has no attribute '__getitem__'

In [37]: Foo.__dict__.get('foo')
Out[37]: 'hello'

原因是在C-API级别,moduletype都是PyTypeObject的特定实例,它们没有实现所需的协议来诱导相同的搜索机制PyTypeObject implementation of object和朋友确实实施了。

要更改语言本身的这一方面,而不是黑客替换sys.modules,您需要更改PyModule_TypePyType_Type的C源定义,以便有C为__getitem__创建的函数,并添加到C-API大PyTypeObject struct-o-magic-functions中的相应位置(其中很多内容由宏PyObject_HEAD展开)而不是{{ 1}}(这是不存在的标记),并使用0module的这些修改后的实现重新编译Python本身。