51 python module python-import
为什么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
Run Code Online (Sandbox Code Playgroud)
Ale*_*lli 83
Python不允许模块覆盖或添加任何魔术方法,因为保持模块对象简单,规则和轻量级是非常有利的,因为很少有强大的用例出现在那里你可以使用魔术方法.
当这样的使用情况做出现,解决的办法是使一个类实例伪装成一个模块.具体来说,编码mod_call.py
如下:
import sys
class mod_call:
def __call__(self):
return 42
sys.modules[__name__] = mod_call()
Run Code Online (Sandbox Code Playgroud)
现在您的代码导入和调用mod_call
工作正常.
Mil*_*les 35
只有在类型上定义特殊方法时,才能保证特殊方法被隐式调用,而不是在实例上定义.(__call__
是模块实例的属性mod_call
,而不是<type 'module'>
.)您无法将方法添加到内置类型.
http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes
Chr*_*ker 10
正如迈尔斯所说,你需要在课堂级别定义调用.因此,Alex post的替代方法是将类更改为类型的sys.modules[__name__]
子类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
Run Code Online (Sandbox Code Playgroud)
注意:使用python3.6测试.
Christoph Böddeker 的答案似乎是创建可调用模块的最佳方法,但正如评论所说,它仅适用于 Python 3.5 及更高版本。
好处是你可以像往常一样编写你的模块,只需在最后添加类重新分配,即
# coolmodule.py
import stuff
var = 33
class MyClass:
...
def function(x, y):
...
class CoolModule(types.ModuleType):
def __call__(self):
return 42
sys.modules[__name__].__class__ = CoolModule
Run Code Online (Sandbox Code Playgroud)
一切正常,包括所有预期的模块属性,如__file__
被定义。(这是因为您实际上根本没有更改由导入产生的模块对象,只是将其“转换”为带有__call__
方法的子类,这正是我们想要的。)
要使其在低于 3.5 的 Python 版本中类似地工作,您可以修改Alex Martelli 的答案,使您的新类成为 ModuleType 的子类,并将所有模块的属性复制到您的新模块实例中:
#(all your module stuff here)
class CoolModule(types.ModuleType):
def __init__(self):
types.ModuleType.__init__(self, __name__)
# or super().__init__(__name__) for Python 3
self.__dict__.update(sys.modules[__name__].__dict__)
def __call__(self):
return 42
sys.modules[__name__] = CoolModule()
Run Code Online (Sandbox Code Playgroud)
现在__file__
,__name__
定义了其他模块属性(如果只是按照亚历克斯的回答,则不存在),并且您导入的模块对象仍然“是”模块。
所有答案仅适用于import mod_call
. 为了让它同时工作from mod_call import *
,@Alex Martelli 的解决方案可以增强如下
import sys
class mod_call:
def __call__(self):
return 42
mod_call = __call__
__all__ = list(set(vars().keys()) - {'__qualname__'}) # for python 2 and 3
sys.modules[__name__] = mod_call()
Run Code Online (Sandbox Code Playgroud)
该解决方案是通过讨论类似问题的答案而得出的。
归档时间: |
|
查看次数: |
14395 次 |
最近记录: |