导出python模块(到字符串或py文件)

时间:2013-08-02 01:11:58

标签: python

要点: 我想采用'module'类型的变量并将其导出。

我正在使用 import 从.py文件导入python模块并对其进行更改。我需要将模块导出回文件或获取完整模块的字符串表示,然后将其写入磁盘。

我一直无法找到任何方法来导出python模块或将模块中的对象转换为结构化,纯文本python可执行格式的字符串的方法。 (不是json,酸洗等)

详细问题&使用案例 此要求是内部构建过程的一部分;没有安全要求,只有我们自己的模块,而不是内置的模块,正在被修改。 python脚本与业务逻辑一起运行以修改许多其他脚本。此过程使用仅在构建时可用的信息。因此,我没有选择在运行时导入具有不同数据的模块。

初始系统使用带有占位符字符串的模板,该模板将被替换,但当前要求需要对对象声明进行更复杂的修改,其中以编程方式修改对象要比字符串替换容易得多。

我做了什么 使用python编写的master生成器脚本,我可以导入多个模块(只有变量声明和没有可执行代码)并进行所需的所有替换。我留下了一个类型模块的变量,我需要将其导出回文件以便稍后执行。

@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',
    },
}

大大简化(并且没有应用任何业务逻辑)我基本上想要执行以下操作:

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)) # 

我希望与我的源文件具有相同的格式,但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'}}

EDITS&澄清: - 我的目标是加载模块,修改它,并将其保存为可执行的python文件。这就是我反对pickle,json等的原因。我需要生成一个可执行的py文件。 - 重写用例以澄清 - 添加了关于我尝试过的事情的例子和更多信息

1 个答案:

答案 0 :(得分:4)

你要求的是不可能的。您正在尝试使用目标代码创建源代码。虽然有反编译器项目可以或多或少地做到这一点,但是一个完全通用的解决方案是难以处理的。

如果您只想获得模块的原始来源,那很容易。例如,您可以使用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')

但是你不能修改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))
  • 如果您非常确定所有值都是可重复的,但不是正面的,那么在写出之前有很多方法可以检查或清理输出。例如:

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))
  • 以适合您的代码生成器,人类读者等的一些不错的格式创建数据文件,而不是尝试生成Python源代码,然后编写简单的Python代码来读取数据文件并在运行时生成对象。