Python:使用 importlib 从字符串动态导入模块的代码

Jos*_*osh 9 python dynamic-import python-3.x python-importlib

我希望在 Python (3.7) 中动态导入一个模块,其中模块的代码在一个字符串中定义。

下面是一个使用该imp模块的工作示例,该模块已被弃用importlib(从 3.4 版开始):

import imp

def import_code(code, name):
    # create blank module
    module = imp.new_module(name)
    # populate the module with code
    exec(code, module.__dict__)
    return module

code = """
def testFunc():
    print('spam!')
"""

m = import_code(code, 'test')
m.testFunc()
Run Code Online (Sandbox Code Playgroud)

Python 的文档说明importlib.util.module_from_spec()应该使用 代替imp.new_module(). 但是,似乎没有办法使用importlib模块创建空白模块对象,就像我可以使用imp.

如何使用importlib而不是imp达到相同的结果?

Rig*_*leg 7

您可以简单地实例化types.Module

import types
mod = types.ModuleType("mod")
Run Code Online (Sandbox Code Playgroud)

然后你可以exec像你一样填充它:

exec(code, mod.__dict__)
mod.testFunc() # will print 'spam!'
Run Code Online (Sandbox Code Playgroud)

所以你的代码看起来像这样:

import types

def import_code(code, name):
    # create blank module
    module = types.ModuleType(name)
    # populate the module with code
    exec(code, module.__dict__)
    return module

code = """
def testFunc():
    print('spam!')
"""

m = import_code(code, 'test')
m.testFunc()
Run Code Online (Sandbox Code Playgroud)

正如@Error - Syntactical Remorse 所评论的那样,您应该记住,exec基本上执行您提供的字符串中包含的任何代码,因此您应该格外小心地使用它。至少检查一下你得到了什么,但最好只使用预定义的字符串。

  • 你可能想添加一个免责声明,他应该只使用预先指定的 `str` 或在调用 `exec` 方法之前检查它们。 (2认同)

小智 5

根据 Python 文档module_from_spec()

importlib.util.module_from_spec(spec)

...

此函数优于使用 types.ModuleType 创建新模块,因为规范用于在模块上设置尽可能多的导入控制属性。

这是我从 github repo 中的源代码加载模块的想法。这是一种无需将文件写入磁盘的方法。

import requests
url = "https://github.com/udacity/deep-learning-v2-pytorch/raw/master/intro-to-pytorch/helper.py"
r = requests.get(url)

import importlib.util
spec = importlib.util.spec_from_loader('helper', loader=None, origin=url)
helper = importlib.util.module_from_spec(spec)
exec(r.content, helper.__dict__)

helper.view_classify() # executes function from github file
Run Code Online (Sandbox Code Playgroud)