3

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

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

我知道我应该使用importlib(需要 Python 3.4+ 就可以了),但我不确定如何:

  1. 使用自定义全局变量加载并执行模块文件。
  2. 重用字节码缓存基础设施。

任何帮助将不胜感激!

4

3 回答 3

1

我研究了importlib的源代码,由于我不打算制作一个可重用的Loader,这似乎有很多不必要的复杂性。所以我只是决定用 来创建一个模块types.ModuleType,添加bld到模块中__dict__,用 编译和缓存字节码compile,然后用exec. 在较低的水平上,这基本上就是一切importutil

于 2017-03-02T01:24:38.430 回答
1

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

对于特定用例,这可能是一个明显或巧妙的解决方案,但它不是很直观。通常,(Python)代码应该是显式的。因此,我会寻求一种解决方案,将参数显式传递给执行代码。听起来像函数?正确的:

文件文件.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来自哪里。

于 2017-03-02T08:15:09.837 回答
0

可以通过使用 dummy 模块来克服这种可能性,该模块将加载其 globals 。

#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 
于 2020-07-04T16:03:40.007 回答