python - 将变量注入(inject)导入命名空间

为了说明我正在尝试做的事情,假设我有一个位于 ./testmod.py 中的模块 testmod。此模块的全部内容是

x = test

我希望能够使用 importlib 或任何其他内置库中可用的任何工具将此模块成功导入 Python。

显然,从当前目录执行简单的 import testmod 语句会导致错误:NameError: name 'test' is not defined

我认为也许将 globalslocals 正确传递给 __import__ 会修改正在运行的脚本内的环境,但它不会:

>>> testmod = __import__('testmod', globals={'test': 'globals'}, locals={'test': 'locals'})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/jfoxrabi/testmod.py", line 1, in <module>
    x = test
NameError: name 'test' is not defined

我设置了不同的 test 值,这样我就可以看到如果可行的话 testmod.x 来自哪个字典。

由于这些似乎都不起作用,所以我被卡住了。甚至有可能完成我想做的事情吗?我想是的,因为这是 Python,而不是 Sparta。

我在 Anaconda 上使用 Python 3.5。我非常不希望使用外部库。

更新:原因

我正在将一个模块作为配置文件导入到我的程序中。我不使用 JSON 或 INI 的原因是我希望 Python 解释器的全部范围可用于从表达式计算配置中的值。我希望在程序中预先计算出某些值,以便进行这些计算。

虽然我知道这与调用 eval 一样糟糕(我在我的程序中也这样做),但我暂时不关心安全方面的问题。但是,如果这确实是 XY 的情况,我非常愿意接受更好的解决方案。

最佳答案

我想出了一个基于 this answer 的解决方案和 importlib docs .基本上,通过使用正确的 importlib 调用顺序,我可以在加载模块对象之前访问它:

from importlib.util import spec_from_file_location, module_from_spec
from os.path import splitext, basename

def loadConfig(fileName):
    test = 'This is a test'
    name = splitext(basename(fileName))[0]
    spec = spec_from_file_location(name, fileName)
    config = module_from_spec(spec)
    config.test = test
    spec.loader.exec_module(config)
    return config

testmod = loadConfig('./testmod.py')

这比修改 builtins 好一点,这可能会对程序的其他部分产生意想不到的后果,并且还可能限制我可以传递给模块的名称。

我决定将所有配置项放入一个在加载时可访问的字段中,我将其命名为 config。这允许我在 testmod 中执行以下操作:

if 'test' in config:
    x = config['test']

加载器现在看起来像这样:

from importlib.util import spec_from_file_location, module_from_spec
from os.path import splitext, basename

def loadConfig(fileName, **kwargs):
    name = splitext(basename(fileName))[0]
    spec = spec_from_file_location(name, fileName)
    config = module_from_spec(spec)
    config.config = kwargs
    spec.loader.exec_module(config)
    return config

testmod = loadConfig('./testmod.py', test='This is a test')

在发现自己多次使用此功能后,我最终将此功能添加到我维护的实用程序库中,haggis . haggis.load.load_module使用注入(inject)将文本文件作为模块加载,而 haggis.load.module_as_dict做一个更高级的版本,将它作为一个潜在的嵌套配置文件加载到 dict 中。

https://stackoverflow.com/questions/38647348/

相关文章:

file - 在同一区域将大文件从 S3 下载到 EC2 的最快方法是什么?

c - ArduinoJSON 未定义对 `__cxa_guard_acquire' 的引用

python - 从 Tkinter Tcl 回调到 python 函数在 Windows 中崩溃

r - 组的总和,但对 r 中的每一行保持相同的值

rx-java - 在 RxJava 中将 Observable 转换为 Collection

php - 如何检查字符串是否包含电子邮件?

validation - 删除 Rails 5 上 belong_to 属性所需的验证

c - 根据 AMD64 ABI,什么样的 C11 数据类型是数组

ruby-on-rails - 是否可以清除 Spring gem 的缓存?

node.js - 应用程序使用(验证器()); ^ 类型错误 : validator is not