首先,在我看来,你可以做两件事......
- 继续追求使用 Python 源文件作为配置文件。(我不会推荐这个。这类似于使用推土机敲钉子或将霰弹枪转换为轮子)
切换到TOML、JSON或YAML之类的配置文件,这些文件专为工作而设计。
JSON 或 YAML 中没有任何内容可以阻止它们持有“有序”的键值对。Python 的dict
数据类型默认是无序的(至少在 3.5 之前)并且list
数据类型是有序的。当使用默认加载器时,它们分别直接映射到 JSON 中的对象和数组。只需在反序列化它们时使用类似 Python 的东西OrderedDict
,瞧,你可以保持秩序!
顺便说一句,如果你真的想使用 Python 源文件进行配置,我建议尝试使用ast
模块处理文件。抽象语法树是语法级别分析的强大工具。
我编写了一个快速脚本,用于从文件中提取类行号和名称。
您(或任何真正的人)可以使用它或将其扩展为更广泛,并且如果您想要任何您想要的东西,可以进行更多检查。
import sys
import ast
import json
class ClassNodeVisitor(ast.NodeVisitor):
def __init__(self):
super(ClassNodeVisitor, self).__init__()
self.class_defs = []
def visit(self, node):
super(ClassNodeVisitor, self).visit(node)
return self.class_defs
def visit_ClassDef(self, node):
self.class_defs.append(node)
def read_file(fpath):
with open(fpath) as f:
return f.read()
def get_classes_from_text(text):
try:
tree = ast.parse(text)
except Exception as e:
raise e
class_extractor = ClassNodeVisitor()
li = []
for definition in class_extractor.visit(tree):
li.append([definition.lineno, definition.name])
return li
def main():
fpath = "/tmp/input_file.py"
try:
text = read_file(fpath)
except Exception as e:
print("Could not load file due to " + repr(e))
return 1
print(json.dumps(get_classes_from_text(text), indent=4))
if __name__ == '__main__':
sys.exit(main())
这是在以下文件上运行的示例:
input_file.py
:
class Foo:
pass
class Bar:
pass
输出:
$ py_to_json.py input_file.py
[
[
1,
"Foo"
],
[
5,
"Bar"
]
]
如果我导入example
,
如果要导入模块,则example
模块要位于导入路径上。导入意味着执行模块中的任何Python 代码example
。这是一个相当大的安全漏洞——您在与应用程序的其余部分相同的上下文中加载用户可编辑的文件。