可调用模块
为什么Python不允许模块有一个 __call__
方法呢?(除了显而易见的直接导入不容易之外。)具体来说,为什么使用 a(b)
这种写法不能像函数、类和对象那样找到 __call__
属性呢?(模块的查找方式是不是有很大的不同?)
>>> print(open("mod_call.py").read())
def __call__():
return 42
>>> import mod_call
>>> mod_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'module' object is not callable
>>> mod_call.__call__()
42
7 个回答
23
正如Miles所说,你需要在类的层面上定义调用。
所以,Alex提到的另一种方法是把sys.modules[__name__]
的类改成它的一个子类(应该是types.ModuleType
)。
这样做的好处是,这个模块可以被调用,同时还能保留模块的其他属性(比如访问函数、变量等等)。
import sys
class MyModule(sys.modules[__name__].__class__):
def __call__(self): # module callable
return 42
sys.modules[__name__].__class__ = MyModule
注意:在python3.6中测试过。
110
Python不允许模块去覆盖或添加任何“魔法方法”,这是因为保持模块对象简单、常规和轻量级是非常有利的,毕竟在实际使用中,能够用到魔法方法的情况非常少。
当这种情况确实出现时,解决办法是让一个类的实例假装成一个模块。具体来说,你可以这样编写你的 mod_call.py
文件:
import sys
class mod_call:
def __call__(self):
return 42
sys.modules[__name__] = mod_call()
现在,你的代码在导入和调用 mod_call
时就可以正常工作了。
46
特殊方法只有在它们被定义在类型上时,才会被隐式调用,而不是在实例上。比如,__call__
是模块实例 mod_call
的一个属性,而不是 <type 'module'>
的属性。你不能给内置类型添加方法。
https://docs.python.org/reference/datamodel.html#special-lookup