希望以下问题不会太长。否则我无法解释我的问题和需求:
从如何使用importlib从任意来源导入模块?(昨天的问题)中学到, 我编写了一个特定的加载器来处理新文件类型(.xxx)。 (实际上,xxx是pyc的加密版本,用于保护代码免受盗窃)。
我希望只是为新文件类型"xxx"添加一个导入钩子,而不以任何方式影响其他类型(.py、.pyc、.pyd)。
现在,加载器是ModuleLoader
,继承自mportlib.machinery.SourcelessFileLoader
。
使用sys.path_hooks
,加载器将被添加为一个钩子:
myFinder = importlib.machinery.FileFinder
loader_details = (ModuleLoader, ['.xxx'])
sys.path_hooks.append(myFinder.path_hook(loader_details))
注意:这是通过调用
modloader.activateLoader()
来激活的。加载名为
test
(它是一个test.xxx
)的模块时,我会得到:>>> import modloader
>>> modloader.activateLoader()
>>> import test
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'test'
>>>
然而,在添加钩子之前删除sys.path_hooks
的内容:
sys.path_hooks = []
sys.path.insert(0, '.') # current directory
sys.path_hooks.append(myFinder.path_hook(loader_details))
它有效:
>>> modloader.activateLoader()
>>> import test
using xxx class
in xxxLoader exec_module
in xxxLoader get_code: .\test.xxx
ANALYZING ...
GENERATE CODE OBJECT ...
2 0 LOAD_CONST 0
3 LOAD_CONST 1 ('foo2')
6 MAKE_FUNCTION 0
9 STORE_NAME 0 (foo2)
12 LOAD_CONST 2 (None)
15 RETURN_VALUE
>>>>>> test
<module 'test' from '.\\test.xxx'>
在将文件内容转换为代码对象后,模块已正确导入。 但是我无法从包中加载相同的模块:
import pack.test
注意:pack
目录中的__init__.py
当然是一个空文件。>>> import pack.test
Traceback (most recent call last):
File "<frozen importlib._bootstrap>", line 2218, in _find_and_load_unlocked
AttributeError: 'module' object has no attribute '__path__'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'pack.test'; 'pack' is not a package
>>>
不够用,我不能再从该软件包中加载普通的 *.py 模块:我会得到与上述相同的错误:
>>> import pack.testpy
Traceback (most recent call last):
File "<frozen importlib._bootstrap>", line 2218, in _find_and_load_unlocked
AttributeError: 'module' object has no attribute '__path__'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'pack.testpy'; 'pack' is not a package
>>>
根据我的理解,
sys.path_hooks
会遍历直到尝试最后一个条目。那么为什么第一种变体(没有删除sys.path_hooks
)不能识别新的扩展名“xxx”,而第二种变体(删除sys.path_hooks
)可以呢?当sys.path_hooks
的一个条目无法识别“xxx”时,似乎机制会抛出异常而不是继续遍历到下一个条目。为什么第二个版本在当前目录中的py、pyc和xxx模块可以正常工作,但在包
pack
中却不能正常工作?我本来以为在当前目录中甚至py和pyc也无法正常工作,因为sys.path_hooks
只包含了一个“xxx”的钩子...
sys.path_hooks.insert(0, myFinder.path_hook(loader_details))
?问题仍然存在。 - Mr_and_Mrs_D