给定完整路径,如何导入模块?

给定完整路径,如何加载 Python 模块?请注意,该文件可以在文件系统中的任何位置,因为它是配置选项。

答案

对于 Python 3.5+,请使用:

import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()

对于 Python 3.3 和 3.4,请使用:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(尽管在 Python 3.4 中已弃用此功能。)

对于 Python 2,请使用:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

编译后的 Python 文件和 DLL 具有等效的便捷功能。

另请参见http://bugs.python.org/issue21436

(通过使用 imp)向 sys.path 添加路径的优点是,当从单个包中导入多个模块时,它可以简化操作。例如:

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

要导入模块,您需要将其目录临时或永久地添加到环境变量中。

暂时

import sys
sys.path.append("/path/to/my/modules/")
import my_module

永久性

将以下行添加到您的.bashrc文件中(在 Linux 中),并在终端中执行source ~/.bashrc

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

信用 / 来源: saarrrr另一个 stackexchange 问题

如果您的顶级模块不是文件,而是与__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 属性” ,如此处所述

听起来您似乎不想专门导入配置文件(它具有很多副作用和其他复杂性),而只想运行它并能够访问生成的名称空间。标准库以runpy.run_path的形式专门提供了一个 API:

from runpy import run_path
settings = run_path("/path/to/file.py")

该接口在 Python 2.7 和 Python 3.2 + 中可用

您还可以执行类似的操作,并将配置文件所在的目录添加到 Python 加载路径,然后假设您事先知道文件名(在本例中为 “config”),则进行常规导入。

凌乱,但有效。

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

您可以使用

load_source(module_name, path_to_file)

来自imp 模块的方法。

我想出了spec_from_loader一个很好的答案的略微修改的版本(我认为是针对 Python> 3.4),它允许您使用spec_from_loader而不是spec_from_file_location加载具有任何扩展名的文件作为模块:

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)

在显式SourceFileLoader对路径进行编码的优点是,该机制不会尝试从扩展名中找出文件的类型。这意味着您可以使用此方法加载.txt文件,但是如果不指定加载程序,则无法使用spec_from_file_location进行加载,因为.txt不在importlib.machinery.SOURCE_SUFFIXES

您是指加载还是导入?

您可以操纵sys.path列表,指定模块的路径,然后导入模块。例如,给定一个模块位于:

/foo/bar.py

您可以这样做:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar

这是一些适用于 2.7-3.5 甚至其他版本的所有 Python 版本的代码。

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

我测试了它可能很丑陋,但到目前为止,它是唯一可以在所有版本中使用的版本。