Post 在 Python 中导入挂钩 3
Post import hooks in Python 3
我希望在导入特定模块时有一些回调 运行。例如(使用不存在的假 @imp.when_imported
函数):
@imp.when_imported('numpy')
def set_linewidth(numpy):
import shutil
numpy.set_printoptions(linewidth=shutil.get_terminal_size()[0])
此功能是在 PEP 369: Post import hooks 中设计的,但已被撤回,原因是:
This PEP has been withdrawn by its author, as much of the detailed design is no longer valid following the migration to importlib in Python 3.3.
但是importlib没有明确的解决办法。如何使用 importlib
实现 post-导入挂钩?
wrapt
模块提供了一个实现。
观看有关 wrapt
的视频,包括以下功能:
认为 wrapt
的文档还没有提到它。
部分博客文章结尾处:
尽管谈谈。
wrapt
有一个名为 autowrapt
的配套模块,它允许您使用此机制进行猴子修补,而无需更改应用程序代码本身来触发它。
这个有用吗?
import importlib
class ImportHook:
def __init__(self, func):
self.func = func
self.module = None
def __enter__(self):
return self
def get_module(self, module_name):
self.module = importlib.import_module(module_name)
return self.module
def __exit__(self, exc_type, exc_val, exc_tb):
if self.module is not None:
self.func(self.module)
def set_linewidth(module):
import shutil
module.set_printoptions(linewidth=shutil.get_terminal_size()[0])
with ImportHook(set_linewidth) as hook:
numpy = hook.get_module('numpy')
我会很震惊地发现这是最好的方法...但是,自早期python2.x版本以来,猴子补丁__import__
已得到支持。我们可以在这里利用它:
try:
import builtins # python3.x
except ImportError:
import __builtin__ as builtins # python2.x
import sys
import collections
_builtin_import = builtins.__import__
def _my_import(name, globals=None, locals=None, fromlist=(), level=0):
already_imported = name in sys.modules
mod = _builtin_import(
name,
globals=globals,
locals=locals,
fromlist=fromlist,
level=level)
if not already_imported and name in _post_import_hooks:
for hook in _post_import_hooks[name]:
hook()
return mod
builtins.__import__ = _my_import
_post_import_hooks = collections.defaultdict(list)
def on_import(name):
def decorator(func):
_post_import_hooks[name].append(func)
return func
return decorator
@on_import('numpy')
def print_hi():
print('Hello Numpy')
print('before numpy')
import numpy
print('after numpy')
这个答案创建了一个 super 用于注册回调的简单注册表。装饰器只是注册函数,然后 returns 它。它不会做任何花哨的检查(例如,模块是否已经加载),但可以很容易地扩展来做到这一点。
显然不利的是,如果某个其他模块决定使用猴子补丁 __import__
,那么您就不走运了——这个模块或另一个模块都可能最终损坏。
我已经测试过了,它似乎适用于 python2.x 和 python3.x。
我希望在导入特定模块时有一些回调 运行。例如(使用不存在的假 @imp.when_imported
函数):
@imp.when_imported('numpy')
def set_linewidth(numpy):
import shutil
numpy.set_printoptions(linewidth=shutil.get_terminal_size()[0])
此功能是在 PEP 369: Post import hooks 中设计的,但已被撤回,原因是:
This PEP has been withdrawn by its author, as much of the detailed design is no longer valid following the migration to importlib in Python 3.3.
但是importlib没有明确的解决办法。如何使用 importlib
实现 post-导入挂钩?
wrapt
模块提供了一个实现。
观看有关 wrapt
的视频,包括以下功能:
认为 wrapt
的文档还没有提到它。
部分博客文章结尾处:
尽管谈谈。
wrapt
有一个名为 autowrapt
的配套模块,它允许您使用此机制进行猴子修补,而无需更改应用程序代码本身来触发它。
这个有用吗?
import importlib
class ImportHook:
def __init__(self, func):
self.func = func
self.module = None
def __enter__(self):
return self
def get_module(self, module_name):
self.module = importlib.import_module(module_name)
return self.module
def __exit__(self, exc_type, exc_val, exc_tb):
if self.module is not None:
self.func(self.module)
def set_linewidth(module):
import shutil
module.set_printoptions(linewidth=shutil.get_terminal_size()[0])
with ImportHook(set_linewidth) as hook:
numpy = hook.get_module('numpy')
我会很震惊地发现这是最好的方法...但是,自早期python2.x版本以来,猴子补丁__import__
已得到支持。我们可以在这里利用它:
try:
import builtins # python3.x
except ImportError:
import __builtin__ as builtins # python2.x
import sys
import collections
_builtin_import = builtins.__import__
def _my_import(name, globals=None, locals=None, fromlist=(), level=0):
already_imported = name in sys.modules
mod = _builtin_import(
name,
globals=globals,
locals=locals,
fromlist=fromlist,
level=level)
if not already_imported and name in _post_import_hooks:
for hook in _post_import_hooks[name]:
hook()
return mod
builtins.__import__ = _my_import
_post_import_hooks = collections.defaultdict(list)
def on_import(name):
def decorator(func):
_post_import_hooks[name].append(func)
return func
return decorator
@on_import('numpy')
def print_hi():
print('Hello Numpy')
print('before numpy')
import numpy
print('after numpy')
这个答案创建了一个 super 用于注册回调的简单注册表。装饰器只是注册函数,然后 returns 它。它不会做任何花哨的检查(例如,模块是否已经加载),但可以很容易地扩展来做到这一点。
显然不利的是,如果某个其他模块决定使用猴子补丁 __import__
,那么您就不走运了——这个模块或另一个模块都可能最终损坏。
我已经测试过了,它似乎适用于 python2.x 和 python3.x。