如何加载给定完整路径的Python模块?
请注意,文件可以位于文件系统中用户具有访问权限的任何位置。
另请参阅:如何导入以字符串形式命名的模块?
如何加载给定完整路径的Python模块?
请注意,文件可以位于文件系统中用户具有访问权限的任何位置。
另请参阅:如何导入以字符串形式命名的模块?
当前回答
这应该行得通
path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
basename = os.path.basename(infile)
basename_without_extension = basename[:-3]
# http://docs.python.org/library/imp.html?highlight=imp#module-imp
imp.load_source(basename_without_extension, infile)
其他回答
向sys.path添加路径(与使用imp相比)的优点是,当从单个包导入多个模块时,可以简化操作。例如:
import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')
from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch
一个使用importlib而不是imp包的简单解决方案(针对Python 2.7进行了测试,尽管它也适用于Python 3):
import importlib
dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")
现在您可以直接使用导入模块的名称空间,如下所示:
a = module.myvar
b = module.myfunc(a)
这种解决方案的优点是,为了在代码中使用它,我们甚至不需要知道要导入的模块的实际名称。这很有用,例如,如果模块的路径是可配置参数。
您可以使用pydoc中的importfile
from pydoc import importfile
module = importfile('/full/path/to/module/module.py')
name = module.myclass() # myclass is a class inside your python file
如果您的顶级模块不是一个文件,而是用__init__.py打包成一个目录,那么接受的解决方案几乎可以工作,但不完全可以。在Python 3.5+中,需要以下代码(请注意添加的以“sys.modules”开头的行):
MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
如果没有这一行,当exec_module被执行时,它会尝试将顶级__init__.py中的相对导入绑定到顶级模块名称——在本例中是“mymodule”。但“mymodule”尚未加载,因此您将收到错误“SystemError:父模块‘mymodule’未加载,无法执行相对导入”。因此,您需要在加载名称之前绑定它。原因是相对导入系统的基本不变:“不变保持是,如果您有sys.modules['spam']和sys.modules['spam.foo'](正如您在上述导入之后所做的那样),后者必须作为前者的foo属性出现”,如这里所讨论的。
可以使用__import__和chdir执行此操作:
def import_file(full_path_to_module):
try:
import os
module_dir, module_file = os.path.split(full_path_to_module)
module_name, module_ext = os.path.splitext(module_file)
save_cwd = os.getcwd()
os.chdir(module_dir)
module_obj = __import__(module_name)
module_obj.__file__ = full_path_to_module
globals()[module_name] = module_obj
os.chdir(save_cwd)
except Exception as e:
raise ImportError(e)
return module_obj
import_file('/home/somebody/somemodule.py')