Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中compile()的可逆版本_Python_Metaprogramming - Fatal编程技术网

Python中compile()的可逆版本

Python中compile()的可逆版本,python,metaprogramming,Python,Metaprogramming,我试图在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”不是) 以下是我尝试过但不起作用的方法:

我试图在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”不是)

以下是我尝试过但不起作用的方法:

  • 在compile返回的代码对象上设置属性。不能在代码对象上设置自定义属性
  • 子类化代码,以便添加属性。代码不能被子类化
  • 设置将代码对象映射到原始字符串的WeakKeyDictionary。代码对象不能被弱引用
以下是解决问题的方法:

  • 为要编译的文件名()传入原始代码字符串。但是,我失去了在那里保存文件名的能力,我也想这样做
  • 保留一个真正的字典,将代码对象映射到字符串。这会泄漏内存,尽管编译很少,但对于我当前的用例来说是可以接受的。如果有必要的话,我可能会定期通过gc运行这些密钥,并杀掉死掉的引用

    • 我的方法是将代码对象包装到另一个对象中。大概是这样的:

      class CodeObjectEnhanced(object):
          def __init__(self, *args):
              self.compiled = compile(*args)
              self.original = args[0]
      def comp(*args):
          return CodeObjectEnhanced(*args)
      
      然后,每当需要代码对象本身时,就使用.compiled,每当需要原始代码时,就使用.original。可能有一种方法可以让eval将新类当作普通的代码对象对待,将函数重定向为调用eval(self.compiled)


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

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

      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]
      


      既然您拥有原始的Python源代码,那么有什么意义呢?
      >>> a = comp('2 * (3 + x)', '', 'eval')
      >>> eval(a, dict(x=3))
      12
      >>> decomp(a)
      '2 * (3 + x)'