所以这是一个非常简单的问题。如何将__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']
。
如果不可能,那么一个简短的理由就是好的。
答案 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)
此限制不仅适用于模块,它适用于类型不是object
或object
的某些子类的任何内容,或具有从不与{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级别,module
和type
都是PyTypeObject
的特定实例,它们没有实现所需的协议来诱导相同的搜索机制PyTypeObject
implementation of object
和朋友确实实施了。
要更改语言本身的这一方面,而不是黑客替换sys.modules
,您需要更改PyModule_Type
和PyType_Type
的C源定义,以便有C为__getitem__
创建的函数,并添加到C-API大PyTypeObject
struct-o-magic-functions中的相应位置(其中很多内容由宏PyObject_HEAD
展开)而不是{{ 1}}(这是不存在的标记),并使用0
和module
的这些修改后的实现重新编译Python本身。