python 可调用模块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1060796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Callable modules
提问by Alex Martelli
Why doesn't Python allow modules to have a __call__
method? (Beyond the obvious that it wouldn't be easy to import directly.) Specifically, why doesn't using a(b)
syntax find the __call__
attribute like it does for functions, classes, and objects? (Is lookup just incompatibly different for modules?)
为什么 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
采纳答案by Miles
Special methods are only guaranteed to be called implicitly when they are defined on the type, not on the instance. (__call__
is an attribute of the module instance mod_call
, not of <type 'module'>
.) You can't add methods to built-in types.
特殊方法只有在类型上定义时才能保证被隐式调用,而不是在实例上。(__call__
是模块实例的一个属性mod_call
,而不是<type 'module'>
。)您不能向内置类型添加方法。
https://docs.python.org/reference/datamodel.html#special-lookup
https://docs.python.org/reference/datamodel.html#special-lookup
回答by Alex Martelli
Python doesn't allow modules to override or add anymagic method, because keeping module objects simple, regular and lightweight is just too advantageous considering how rarely strong use cases appear where you could use magic methods there.
Python 不允许模块覆盖或添加任何魔术方法,因为考虑到很少出现可以在那里使用魔术方法的强大用例,保持模块对象简单、常规和轻量级是非常有利的。
When such use cases doappear, the solution is to make a class instance masquerade as a module. Specifically, code your mod_call.py
as follows:
当此类用例确实出现时,解决方案是将类实例伪装成模块。具体来说,代码mod_call.py
如下:
import sys
class mod_call:
def __call__(self):
return 42
sys.modules[__name__] = mod_call()
Now your code importing and calling mod_call
works fine.
现在您的代码导入和调用mod_call
工作正常。
回答by Christoph B?ddeker
As Miles says, you need to define the call on class level.
So an alternative to Alex post is to change the class of sys.modules[__name__]
to a subclass of the type of sys.modules[__name__]
(It should be types.ModuleType
).
正如 Miles 所说,您需要在类级别定义调用。因此,Alex post 的替代方法是将 的类更改sys.modules[__name__]
为sys.modules[__name__]
( 应该是types.ModuleType
)类型的子类。
This has the advantage that the module is callable while keeping all other properties of the module (like accessing functions, variables, ...).
这样做的好处是模块是可调用的,同时保持模块的所有其他属性(如访问函数、变量等)。
import sys
class MyModule(sys.modules[__name__].__class__):
def __call__(self): # module callable
return 42
sys.modules[__name__].__class__ = MyModule
Note: Tested with python3.6.
注意:用python3.6测试。
回答by Nick Matteo
Christoph B?ddeker's answerseems to be the best way to create a callable module, but as a commentsays, it only works in Python 3.5 and up.
Christoph B?ddeker 的答案似乎是创建可调用模块的最佳方法,但正如评论所说,它仅适用于 Python 3.5 及更高版本。
The benefit is that you can write your module like normal, and just add the class reassignment at the very end, i.e.
好处是你可以像往常一样编写你的模块,只需在最后添加类重新分配,即
# 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
and everything works, including all expected module attributes like __file__
being defined. (This is because you're actually not changing the module object resulting from the import at all, just "casting" it to a subclass with a __call__
method, which is exactly what we want.)
一切正常,包括所有预期的模块属性,如__file__
被定义。(这是因为您实际上根本没有更改由导入产生的模块对象,只是将其“转换”为带有__call__
方法的子类,这正是我们想要的。)
To get this to work similarly in Python versions below 3.5, you can adapt Alex Martelli's answerto make your new class a subclass of ModuleType, and copy all the module's attributes into your new module instance:
要使其在低于 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()
Now __file__
, __name__
and other module attributes are defined (which aren't present if just following Alex's answer), and your imported module object still "is a" module.
现在__file__
,__name__
定义了其他模块属性(如果只是按照亚历克斯的回答,则不存在),并且您导入的模块对象仍然“是”模块。
回答by Friedrich
All answers work only for import mod_call
. To get it working also for from mod_call import *
, the solution of @Alex Martelli can be enhanced as follow
所有答案仅适用于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()
This solution was derived with the discussion of an answerof a similar problem.