【问题标题】:Reversible version of compile() in PythonPython 中 compile() 的可逆版本
【发布时间】:2010-10-17 15:42:10
【问题描述】:

我正在尝试在 Python 中创建一个与 compile() 等效的函数,但也可以让我取回原始字符串。为了消除歧义,我们将这两个函数称为 comp() 和 decomp()。也就是说,

a = comp("2 * (3 + x)", "", "eval")
eval(a, dict(x=3)) # => 12
decomp(a) # => "2 * (3 + x)"

返回的字符串不必相同(“2*(3+x)”可以接受),但需要基本相同(“2 * x + 6”不会)。

这是我尝试过的不起作用的方法:

  • 在编译返回的代码对象上设置一个属性。您不能在代码对象上设置自定义属性。
  • 子类化代码,以便我可以添加属性。代码不能被子类化。
  • 设置 WeakKeyDictionary 将代码对象映射到原始字符串。代码对象不能被弱引用。

以下是可行的方法,但有问题:

  • 将文件名的原始代码字符串传递给 compile()。但是,我失去了在其中实际保留文件名的能力,我也想这样做。
  • 保留将代码对象映射到字符串的真实字典。这会泄漏内存,尽管由于编译很少见,但对于我当前的用例来说是可以接受的。如果必须的话,我可能可以定期通过 gc.get_referrers 运行密钥并杀死死掉的密钥。

【问题讨论】:

  • 既然你有原始的 Python 源码,那还有什么意义呢?

标签: python metaprogramming


【解决方案1】:

这是一个奇怪的问题,我最初的反应是,你最好完全做其他事情来完成你想做的任何事情。但这仍然是一个有趣的问题,所以这是我的破解之道:我将原始代码源设为代码对象的未使用常量。

import types

def comp(source, *args, **kwargs):
    """Compile the source string; takes the same arguments as builtin compile().
    Modifies the resulting code object so that the original source can be
    recovered with decomp()."""
    c = compile(source, *args, **kwargs)
    return types.CodeType(c.co_argcount, c.co_nlocals, c.co_stacksize, 
        c.co_flags, c.co_code, c.co_consts + (source,), c.co_names, 
        c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno, 
        c.co_lnotab, c.co_freevars, c.co_cellvars)

def decomp(code_object):
    return code_object.co_consts[-1]

>>> a = comp('2 * (3 + x)', '', 'eval')
>>> eval(a, dict(x=3))
12
>>> decomp(a)
'2 * (3 + x)'

【讨论】:

    【解决方案2】:

    我的方法是将代码对象包装在另一个对象中。像这样的:

    class CodeObjectEnhanced(object):
        def __init__(self, *args):
            self.compiled = compile(*args)
            self.original = args[0]
    def comp(*args):
        return CodeObjectEnhanced(*args)
    

    然后,每当您需要代码对象本身时,就使用 a.compiled,而每当您需要原始代码时,就使用 a.original。可能有一种方法可以让 eval 将新类视为普通代码对象,将函数重定向为调用 eval(self.compiled)。

    这样做的一个好处是原始字符串与代码对象同时被删除。不管你怎么做,我认为存储原始字符串可能是最好的方法,因为你最终会得到你使用的确切字符串,而不仅仅是一个近似值。

    【讨论】:

      猜你喜欢
      • 2022-12-21
      • 1970-01-01
      • 2012-01-17
      • 2011-01-28
      • 2010-11-06
      • 2016-06-06
      • 2021-12-28
      • 1970-01-01
      • 2012-02-21
      相关资源
      最近更新 更多