如何使用importlib加载带有自定义全局变量的Python模块?

时间:2017-03-01 21:17:25

标签: python python-module python-importlib

我试图在Python中组建一个小型构建系统,为我的C ++项目生成Ninja文件。它的行为应该类似于CMake;也就是说,that.setState() 脚本定义规则和目标,并可选择通过调用bldfile.py将其递归到一个或多个目录中。每个bld.subdir()脚本都有一个对应的bldfile.py对象。执行bld.File脚本时,bldfile.py全局应预定义为该文件的bld实例,但仅限于该模块的范围

此外,我想以某种方式利用Python的字节码缓存,但bld.File文件应该存储在构建输出目录中,而不是存储在.pyc目录旁边的__pycache__目录中。 {1}}脚本。

我知道我应该使用bldfile.py(要求Python 3.4+很好),但我不确定如何:

  1. 使用自定义全局变量加载并执行模块文件。
  2. 重用字节码缓存基础架构。
  3. 非常感谢任何帮助!

3 个答案:

答案 0 :(得分:1)

我研究了importlib的源代码,因为我不打算重复使用Loader,所以看起来似乎有很多不必要的复杂性。所以我决定使用types.ModuleType创建一个模块,将bld添加到模块的__dict__,使用compile编译和缓存字节码,并使用{{1}执行模块}}。在较低的水平上,无论如何基本上都是exec

答案 1 :(得分:1)

在执行之前将全局变量注入模块是一个有趣的想法。但是,我认为它与Zen of Python的几个点有冲突。特别是,它需要在模块中编写代码,该代码依赖于未明确定义,导入或以其他方式获得的全局值 - 除非您知道调用模块所需的特定过程。

对于特定用例,这可能是一个明显或光滑的解决方案,但它不是非常直观。通常,(Python)代码应该是显式的。因此,我会寻求一个解决方案,其中参数显式传递给执行代码。听起来像功能?右:

<强> bldfile.py

def exec(bld):
    print('Working with bld:', bld)
    # ...

调用模块:

# set bld

# Option 1: static import
import bldfile
bldfile.exec(bld)

# Option 2: dynamic import if bldfile.py is located dynamically
import importlib.util
spec = importlib.util.spec_from_file_location("unique_name", "subdir/subsubdir/bldfile.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
module.exec(bld)

这样,导入模块时不会执行任何代码(除了函数定义)。需要明确调用exec函数,在查看exec中的代码时,bld来自何处。

答案 2 :(得分:0)

可以使用虚拟模块克服这种可能性的不足,该模块将加载其全局变量。

#service.py 
module = importlib.import_module('userset')
module.user = user 
module = importlib.import_module('config')

#config.py
from userset import *
#now you can use user from service.py