您在这里遇到两个基本问题:
-
__xxx__
方法仅在类上查找
TypeError: can't set attributes of built-in/extension type 'module'
(1) 意味着任何解决方案都必须跟踪正在检查的模块,否则every然后模块将具有实例替换行为; (2) 意味着 (1) 甚至不可能......至少不是直接可能。
幸运的是,sys.modules 对那里的内容并不挑剔,因此包装器可以工作,但仅适用于模块访问(即import somemodule; somemodule.salutation('world')
;对于相同模块的访问,您几乎必须从替换类中取出方法并将它们添加到globals()
在类上使用自定义方法(我喜欢使用.export()
)或使用通用函数(例如已列为答案的函数)。需要记住的一件事是:如果包装器每次都创建一个新实例,而全局解决方案则不然,那么您最终会得到略有不同的行为。哦,你不能同时使用两者——只能是其中之一。
Update
From 吉多·范罗苏姆 http://mail.python.org/pipermail/python-ideas/2012-May/014969.html:
实际上有一个偶尔使用和推荐的 hack:
模块可以定义一个具有所需功能的类,然后在
最后,用该类的实例替换 sys.modules 中的自身
(或者如果你坚持的话,也可以在课堂上,但这通常不太有用)。
例如。:
# module foo.py
import sys
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
sys.modules[__name__] = Foo()
这是有效的,因为进口机械正在积极实现这一目标
hack,最后一步将实际模块从
sys.modules,加载后。 (这并非偶然。黑客攻击是
很久以前就提出了,我们决定我们足够喜欢支持它
进口机械。)
因此,完成您想要的任务的既定方法是在模块中创建一个类,并作为模块的最后一个动作替换sys.modules[__name__]
与你的班级的一个实例 - 现在你可以玩__getattr__
/__setattr__
/__getattribute__
如所须。
Note 1:如果您使用此功能,则模块中的其他任何内容(例如全局变量、其他函数等)都将在sys.modules
分配已经完成——因此请确保所需的一切都在替换类中。
Note 2: 支持from module import *
你必须有__all__
在类中定义;例如:
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
__all__ = list(set(vars().keys()) - {'__module__', '__qualname__'})
根据您的 Python 版本,可能还有其他名称需要省略__all__
. The set()
如果不需要 Python 2 兼容性,可以省略。