摘要: 我想使用“模块”类型的变量并将其导出。
我正在使用import从.py文件中导入 python模块并对其进行更改。我需要将模块导出回文件或获取完整模块的字符串表示形式,然后可以将其写入磁盘。
我一直找不到任何方法可以导出python模块,也无法将模块内的对象转换为结构化,纯文本python可执行格式的字符串。(不是json,腌制等)
详细的问题和用例: 此要求是内部构建过程的一部分;没有安全要求,仅修改了我们自己的模块,而不是内置模块。python脚本与业务逻辑一起运行以修改许多其他脚本。此过程使用仅在构建时可用的信息。结果,我无法选择在运行时导入具有不同数据的模块。
最初的系统使用了带有占位符字符串的模板,该模板将被替换,但是当前的要求要求对对象声明进行更复杂的修改,其中以编程方式修改对象比替换字符串要容易得多。
我所做的事情 使用python编写的主生成器脚本,我可以导入多个模块(它们只有变量声明,没有可执行代码),并进行所有需要的替换。我剩下一个模块类型的变量,我需要将其导出回文件以供以后执行。
@abarnert有一些好主意。我不知道repr功能。那给了我信息,但没有任何格式。这使我看到了pprint,它与到目前为止我所想要的接近。
示例 example.py
sample = {
'level1_dict_1' : {
'key1' : 'value1',
'key2' : {
'level2_dict' : {
'key1' : 'value3',
'key2' : ['list1','list2','list3','list4'],
}
}
},
'level1_dict_2' : {
'key1' : 'value1',
'key2' : 'value2',
},
}
Run Code Online (Sandbox Code Playgroud)
大大简化了(并且没有应用任何业务逻辑),我基本上想执行以下操作:
with open("example.py","w") as outfile:
example = __import__('example') # Import module
example.sample['level1_dict_1']['key2']['level2_dict']['key2'][2] = "newlistitem3" # Change 1 property in a list nested a few levels deep
outfile.write("sample = \n" + pprint.pformat(example.sample)) #
Run Code Online (Sandbox Code Playgroud)
我希望格式与源文件相同,但pprint虽然可读,但格式却与我所希望的不同。这可能与我所需要的尽可能接近。
pprint输出:
sample =
{'level1_dict_1': {'key1': 'value1',
'key2': {'level2_dict': {'key1': 'value3',
'key2': ['list1',
'list2',
'newlistitem3',
'list4']}}},
'level1_dict_2': {'key1': 'value1', 'key2': 'value2'}}
Run Code Online (Sandbox Code Playgroud)
编辑与说明:-我的目标是加载模块,对其进行修改,然后将其另存为可执行python文件。这就是我反对泡菜,json等的原因。我需要产生一个可执行的py文件。-重新编写用例以进行澄清-添加了示例和有关我尝试过的事情的更多信息
您要的是不可能的。您正在尝试使用目标代码创建源代码。尽管有一些反编译项目可以或多或少地做到这一点,但是一个完全通用的解决方案却很难。
如果您只想获取模块的原始来源,那很容易。例如,您可以使用inspect.getsource,然后将结果字符串写入文件。或者只是使用inspect.getfile并从结果路径名复制。
您当然可以在复制原始源文件时对其进行修改。例如:
source = inspect.getsource(foo)
with open('newfoo.py', 'wb') as f:
f.write(source)
f.write('spam = Spam(3)\neggs = Eggs(spam)\n')
Run Code Online (Sandbox Code Playgroud)
但是您不能修改foo然后重新生成其源。
但是,可能有更好的方法来做您真正需要做的事情。例如:
使用JSON,pickle(模式0),YAML等。尽管您声明了什么,但它们是结构化的,可读的纯文本格式,就像Python源一样。
使用repr。对于字符串,数字和内置常数文字,以及仅包含(递归地)上述类型的列表和字典,repr都是可双向访问的。例如:
with open('newfoo.py', 'wb') as f:
for name, value in foo.__dict__.items():
f.write('{} = {!r}\n'.format(name, value))
Run Code Online (Sandbox Code Playgroud)
with open('newfoo.py', 'wb') as f:
for name, value in foo.__dict__.items():
if ast.literal_eval(repr(value)) != value:
raise ValueError('Tried to save {}'.format(value))
f.write('{} = {!r}\n'.format(name, value))
Run Code Online (Sandbox Code Playgroud)