我正在寻找一个从文件名加载和返回模块的Python例程,即使之前导入了具有该名称或该文件名的模块。
更具体地说,我想编写一个通过以下测试的函数unconditional_import
:
import os
def make_module(folder, filename, version):
try: os.mkdir(folder)
except OSError: pass
f = open(os.path.join(folder,filename), "w")
f.write("version = %i" % version)
f.close()
make_module("test","spam.py", 1)
assert( unconditional_import("test","spam.py").version == 1 )
make_module("test","more_spam.py", 2)
assert( unconditional_import("test","more_spam.py").version == 2 )
make_module("test","more_spam.py", 3)
assert( unconditional_import("test","more_spam.py").version == 3 )
make_module("test2","more_spam.py", 4)
assert( unconditional_import("test2","more_spam.py").version == 4 )
我找到了一个解决方案(我将发布作为保持结构的答案),但它相当丑陋并且感觉不健壮。我希望有一些更简单的原生方式来做到这一点,但我找不到它。
注意:
我知道How to import a module given the full path?,它解决了如何从路径导入模块,但只能运行一次。
我知道在大多数情况下,人们只会重新加载翻译,但这对我来说不是一个选择。
答案 0 :(得分:2)
到目前为止,我的最佳解决方案是:
def unconditional_import(folder, filename):
full_path = os.path.join(folder,filename)
if os.path.isfile(full_path+"c"):
os.remove(full_path+"c")
cachefolder = os.path.join(folder,"__pycache__")
if os.path.isdir(cachefolder):
for f in os.listdir(cachefolder):
if f.startswith(filename.rstrip(".py")) and f.endswith(".pyc"):
os.remove(os.path.join(cachefolder,f))
if sys.version_info < (3,0):
from imp import load_source
foo = load_source("foo", full_path)
elif sys.version_info < (3,5):
from importlib.machinery import SourceFileLoader
foo_module = SourceFileLoader("foo", full_path)
foo = foo_module.load_module()
else:
from importlib.util import spec_from_file_location, module_from_spec
spec = spec_from_file_location("foo", full_path)
foo = module_from_spec(spec)
spec.loader.exec_module(foo)
return foo
问题和注意事项:
我无法测试Python 3.5及更高版本的变体,但我认为没有理由说它不起作用或为什么会有更简单的解决方案。
手动删除PYC文件让我感到畏缩,我希望它会引起问题。