如何加载给定完整路径的Python模块?

请注意,文件可以位于文件系统中用户具有访问权限的任何位置。


另请参阅:如何导入以字符串形式命名的模块?


当前回答

这将允许在3.4中导入编译的(pyd)Python模块:

import sys
import importlib.machinery

def load_module(name, filename):
    # If the Loader finds the module name in this list it will use
    # module_name.__file__ instead so we need to delete it here
    if name in sys.modules:
        del sys.modules[name]
    loader = importlib.machinery.ExtensionFileLoader(name, filename)
    module = loader.load_module()
    locals()[name] = module
    globals()[name] = module

load_module('something', r'C:\Path\To\something.pyd')
something.do_something()

其他回答

听起来您不想专门导入配置文件(这会带来很多副作用和额外的复杂性)。您只需要运行它,并能够访问生成的命名空间。标准库以runpy.run_path的形式专门提供了一个API:

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

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

我发现这是一个简单的答案:

module = dict()

code = """
import json

def testhi() :
    return json.dumps({"key" : "value"}, indent = 4 )
"""

exec(code, module)
x = module['testhi']()
print(x)

我并不是说它更好,但为了完整起见,我想建议在Python2和Python3中使用exec函数。

exec允许您在全局作用域或作为字典提供的内部作用域中执行任意代码。

例如,如果您有一个模块存储在带有函数foo()的“/path/to/module”中,您可以通过执行以下操作来运行它:

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

这使得动态加载代码更加明确,并赋予您一些额外的功能,例如提供自定义内置功能的能力。

如果通过属性而不是键访问对你来说很重要,你可以为全局变量设计一个自定义dict类,提供这样的访问,例如:

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)

一个使用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)

这种解决方案的优点是,为了在代码中使用它,我们甚至不需要知道要导入的模块的实际名称。这很有用,例如,如果模块的路径是可配置参数。

对于Python 3.5+,使用(docs):

import importlib.util
import sys
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
sys.modules["module.name"] = foo
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.