2009-04-05 10 views
3

私はPythonでcompile()と同等の機能を実現しようとしていますが、元の文字列を戻すこともできます。曖昧さ回避のために、これら2つの関数comp()とdecomp()を呼び出してみましょう。すなわち、Pythonでのコンパイル()の可逆バージョン

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

ある」(2 * X +が返される文字列は、( "2×(3 + X)" に許容されるであろう)同じである必要はないが、それは基本的に同じである必要があります6 "はそうではない)。コンパイルによって返されたコードオブジェクトの属性を設定する

  • は、ここで私はがない作業を行うことを試みたものです。コードオブジェクトにカスタム属性を設定することはできません。

  • コードをサブクラス化するので、属性を追加できます。コードをサブクラス化することはできません。
  • コードオブジェクトを元の文字列にマッピングするWeakKeyDictionaryを設定します。コードオブジェクトを弱く参照することはできません。 ()をコンパイルするファイル名の元のコードの文字列を渡す

    • :ここ

    は問題に、仕事をするものです。しかし、実際にファイル名を保持する機能は失われてしまいます。これもやりたいことです。

  • コードオブジェクトを文字列にマッピングする実際の辞書の保持。コンパイルはまれですが、現在のユースケースでは受け入れられますが、これはメモリをリークします。おそらく、gc.get_referrersを使ってキーを定期的に実行し、死んだものを殺すことができます。
+0

あなたは、元のPythonのソースを持っているので、ポイントは何ですか? –

答えて

6

これは奇妙な問題です。私の初期の反応は、あなたが何をしようとしているのかを完全に達成するために他の何かを行うことをお勧めします。しかし、それはまだ興味深い質問ですので、ここで私の亀裂です:私は元のコードソースをコードオブジェクトの未使用の定数にします。

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)' 
4

私のアプローチは、コードオブジェクトを別のオブジェクトにラップすることです。このような何か:あなたはコードオブジェクト自体を必要なとき

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)を呼び出すようにリダイレクトする方法があるかもしれません。

この利点の1つは、元の文字列がコードオブジェクトと同時に削除されることです。しかし、これを行うと、元の文字列を格納するのがおそらく最善のアプローチであると思います。

関連する問題