Ero*_*mic 5 python import module
所以,我知道我可以加载一个 python 模块,给定一个模块的文件路径
def import_module_from_fpath(module_fpath):
from os.path import basename, splitext, isdir, join, exists, dirname, split
import platform
if isdir(module_fpath):
module_fpath = join(module_fpath, '__init__.py')
print('module_fpath = {!r}'.format(module_fpath))
if not exists(module_fpath):
raise ImportError('module_fpath={!r} does not exist'.format(
module_fpath))
python_version = platform.python_version()
modname = splitext(basename(module_fpath))[0]
if modname == '__init__':
modname = split(dirname(module_fpath))[1]
if python_version.startswith('2.7'):
import imp
module = imp.load_source(modname, module_fpath)
elif python_version.startswith('3'):
import importlib.machinery
loader = importlib.machinery.SourceFileLoader(modname, module_fpath)
module = loader.load_module()
# module = loader.exec_module(modname)
else:
raise AssertionError('invalid python version={!r}'.format(
python_version))
return module
Run Code Online (Sandbox Code Playgroud)
然而,这似乎总是填充sys.modules
?中的条目。
我的情况是,我在不同的路径中有两个不同的模块。无法从 PYTHONPATH 访问这两个模块。我希望能够在不同的函数中本地加载这些模块,并且不让它们相互干扰。这个问题的关键是两个模块具有相同的名称(不同的版本)。因此,我不想sys.modules
缓存中间的任何内容。
我不确定sys.modules
加载模块后简单地删除模块名称是否安全。看来这可能来自我所做的快速测试:
import shutil
import ubelt as ub
test_root = ub.ensure_app_cache_dir('test_fpath_import')
# Clear the directory
shutil.rmtree(test_root)
test_root = ub.ensure_app_cache_dir('test_fpath_import')
# -----
# Define two temporary modules with the same name that are not in sys.path
import sys, os, os.path
from os.path import join
# Even though they have the same name they have different values
mod1_fpath = ub.ensuredir((test_root, 'path1', 'testmod'))
ub.writeto(join(mod1_fpath, '__init__.py'), 'version = 1\nfrom . import sibling\na1 = 1')
ub.writeto(join(mod1_fpath, 'sibling.py'), 'spam = \"ham\"\nb1 = 2')
# Even though they have the same name they have different values
mod2_fpath = ub.ensuredir((test_root, 'path2', 'testmod'))
ub.writeto(join(mod2_fpath, '__init__.py'), 'version = 2\nfrom . import sibling\na2 = 3')
ub.writeto(join(mod2_fpath, 'sibling.py'), 'spam = \"jam\"\nb2 = 4')
# -----
# Neither module should be importable through the normal mechanism
try:
import testmod
assert False, 'should fail'
except ImportError as ex:
pass
mod1 = import_module_from_fpath(mod1_fpath)
print('mod1.version = {!r}'.format(mod1.version))
print('mod1.version = {!r}'.format(mod1.version))
print(mod1.version == 1, 'mod1 version is 1')
print('mod1.a1 = {!r}'.format(mod1.a1))
mod2 = import_module_from_fpath(mod2_fpath)
print('mod2.version = {!r}'.format(mod2.version))
print(mod2.version == 2, 'mod2 version is 2')
print('mod2.a2 = {!r}'.format(mod1.a2))
# BUT Notice how mod1 is mod2
print(mod1 is mod2)
# mod1 has attributes from mod1 and mod2
print('mod1.a1 = {!r}'.format(mod1.a1))
print('mod1.a2 = {!r}'.format(mod1.a2))
print('mod2.a1 = {!r}'.format(mod2.a1))
print('mod2.a2 = {!r}'.format(mod2.a2))
# Both are version 2
print('mod1.version = {!r}'.format(mod1.version))
print('mod2.version = {!r}'.format(mod2.version))
# However sibling always remains at version1 (ham)
print('mod2.sibling.spam = {!r}'.format(mod2.sibling.spam))
# now importing testmod works because it reads from sys.modules
import testmod
# reloading mod1 overwrites attrs again
mod1 = ut.import_module_from_fpath(mod1_fpath)
# Removing both from sys.modules
del sys.modules['testmod']
del sys.modules['testmod.sibling']
mod2 = ut.import_module_from_fpath(mod2_fpath)
print(not hasattr(mod2, 'a1'),
'mod2 no longer has a1 and it reloads itself correctly')
Run Code Online (Sandbox Code Playgroud)
上面的脚本说明了尝试加载两个具有相同名称的不同模块时会发生什么:它们相互覆盖/互补。但是,如果我执行此导入,然后直接删除所有导入的模块,它似乎做了“正确”的事情。
我的问题是:
它真的在做“正确”的事吗?或者是否存在我的脚本未测试的情况。
有没有办法在本地导入模块而不将其添加到sys.modules
(也称为全局命名空间)?(是sys.modules
构成模块全局命名空间的唯一东西吗?)
(我只在Python 3中测试了上面的代码,不确定旧imp
模块是否做同样的事情importlib
)。
您可以使用配方直接从文档中导入源文件,同时跳过语句,该语句将模块对象存储在.importlib
sys.modules[module_name] = module
sys.modules
例如,如果您有module.py
:
foo = 1
Run Code Online (Sandbox Code Playgroud)
然后以下内容将导入module.py
,而不创建inmodule
条目:'module'
sys.modules
import sys
from importlib.util import spec_from_file_location, module_from_spec
spec = spec_from_file_location('module', 'module.py')
module = module_from_spec(spec)
spec.loader.exec_module(module)
print(module.foo)
print('module' in sys.modules)
Run Code Online (Sandbox Code Playgroud)
这输出:
1
False
Run Code Online (Sandbox Code Playgroud)
演示: https: //replit.com/@blhsing1/JampackedEverternityJavabeans
归档时间: |
|
查看次数: |
1048 次 |
最近记录: |