我想修改导入行为。我在David Beazley和Brian K.Jones的"Python Cookbook“一书中找到了一个post导入钩子的例子,它应该适合我的问题。
由于最新版本是在python-3.3时代发布的,因此提供的示例已过时。我不得不自己修改它,以便代码在python-3.4之后与importlib兼容。在最初的版本中,在PostImportFinder中定义了find_module(self, fullname, path = None)类,在PostImportLoader中定义了load_module(),而不是create_module()。下面是一个可重复使用的小示例:
#postimport.py
import
import importlib
import sys
from collections import defaultdict
_post_import_hooks = defaultdict(list)
class PostImportFinder:
def __init__(self):
self._skip=set()
def find_spec(self, fullname, path = None, target = None):
if fullname in self._skip:
return None
self._skip.add(fullname)
return PostImportLoader(self)
class PostImportLoader:
def __init__(self, finder):
self._finder = finder
def create_module(self, spec):
importlib.import_module(spec.name)
module = sys.modules[spec.name]
for func in _post_import_hooks[spec.name]:
func(module)
self._finder._skip.remove(spec.name)
return module
def when_imported(names):
def decorate(func):
for fullname in names:
if fullname in sys.modules:
print(f'importing {fullname}')
func(sys.modules[fullname])
else:
_post_import_hooks[fullname].append(func)
return func
return decorate
sys.meta_path.insert(0,PostImportFinder)#postimportfunc.py
from inspect import getmembers, isfunction, isclass
from postimport import when_imported
list_of_module_names = ['simple']
#Some decorator. For example purposes pretty simple
@when_imported(list_of_module_names)
def decorate(mod):
# Decorate classes
print(f'module {mod} imported')#simple.py
class A:
def __init__(self):
self.x=42
def bar(self):
print(self.x)#start.py
import postimportfunc
from simple import A
foo = A()
foo.bar()当我运行start.py时,出现以下错误:
runfile('/home/user/reproduce/start.py', wdir='/home/user/reproduce')
File "/usr/lib/python3/dist-packages/spyder_kernels/customize/spydercustomize.py", line 827, in runfile
execfile(filename, namespace)
File "/usr/lib/python3/dist-packages/spyder_kernels/customize/spydercustomize.py", line 110, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "/home/user/reproduce/start.py", line 2, in <module>
import postimportfunc
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 971, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 914, in _find_spec
File "/home/user/reproduce/postimport.py", line 12, in find_spec
if fullname in self._skip:
AttributeError: 'str' object has no attribute '_skip' 所以我的问题很明显:我做错了什么?我根本看不出_skip和str有什么关系,因为我把_skip初始化为一个集合。有没有其他/更好的方法来改变指定模块的移植后行为?
更新:另外,我忘了提一下,我目前使用的是python-3.7。
发布于 2021-10-17 22:05:51
主要原因是postimport.py最后一行中的一个愚蠢的打字错误。而不是:
sys.meta_path.insert(0,PostImportFinder)它应该是:
sys.meta_path.insert(0,PostImportFinder()) #DO NOT FORGET PARENTHESIS但这并不是唯一的问题。我还必须更改以下内容:
在PostImportFinder中,将find_spec(self, fullname, path = None, targer = None)重命名为find_module(self, fullname, path = None),在PostImportLoader中,将find_spec()替换为:
def load_module(self, fullname):
importlib.import_module(fullname)
module = sys.modules[fullname]
for func in _post_import_hooks[fullname]:
func(module)
self._finder._skip.remove(fullname)
return module所以,总结一下:我应该坚持问题中提到的书中的食谱。
https://stackoverflow.com/questions/69608322
复制相似问题