Reverse compilation version () in Python

I am trying to make a function in Python that does the equivalent of compile (), but also allows me to return the original string. Let the two functions be called comp () and decomp () for disambiguation purposes. I.e

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

The returned string does not have to be identical ("2 * (3 + x)" will be acceptable), but it should be basically the same ("2 * x + 6" will not).

Here is what I tried, which does not work:

  • Setting the attribute of the code object returned by the compilation. You cannot set custom attributes for code objects.
  • Subclass code, so I can add an attribute. code cannot be a subclass.
  • Setting WeakKeyDictionary display code objects for source strings. code objects cannot be weakly specified.

Here's what works with the problems:

  • Passing the source line of code for the file name to compile (). However, I am losing the ability to actually store the file name there, which I would also like to do.
  • Saving a real dictionary that maps code objects to strings. This is a memory leak, although since compilation is rare, this is acceptable for my current use case. Perhaps I could periodically run keys through gc.get_referrers and kill the dead if I had to.
+3
source share
2 answers

, , - , , . , : .

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)'
+6

, . - :

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

, . , , , , , , , .

+4

Source: https://habr.com/ru/post/1705928/


All Articles