2017-05-05 9 views
0

私はpickleをcompile/execで使用したいが、私にとってはうまくいかない。これは、グローバル名前空間を使用する場合にのみ機能します。しかし、私はグローバルな名前空間を使いたくないのですが、そこにはどんな方法がありますか?ありがとうございましたpyleがコンパイル/ execで動作しない

>>> a = compile("def f():\n\t'hello'\nimport pickle\npickle.dumps(f)", "<stdin>", "exec") 
>>> exec(a)   # works 
>>> exec(a, {})  # fails 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in <module> 
_pickle.PicklingError: Can't pickle <function f at 0x1050881e0>: it's not the same object as __main__.f 
>>> exec(a, {'__name__': '__main__'}) # fails too 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in <module> 
_pickle.PicklingError: Can't pickle <function f at 0x1050882f0>: it's not the same object as __main__.f 
+0

'ディル'ピクルス機能と動作する必要があります。 – tdelaney

+0

@tdelaney申し訳ありませんが、私はそれを取得しない、あなたはもっと説明できますか? Thanks – zjffdu

+0

'pickle'は、関数のテキスト名を保存しますが、関数オブジェクト自体は保存しません。 unpicklerは関数を取得するためにモジュールをインポートする必要があります。最初のケースでは、関数をトップレベルスクリプトのグローバル名前空間にバインドしました。その名前空間は '__main__'と呼ばれるので、' __main__'というモジュールをロードしてその 'f'関数を使うためのpickle命令でした。 '__main__'も' f'も見つからないので、うまく動作しませんでした。 'dill'は機能自体を漬け込み、あなたのために働く機会が増えます。 – tdelaney

答えて

1

いいえ、これを行う方法はありません(いずれにしても妥当な方法はありません)。関数は、修飾された名前でpickleを実行しますが、実際には実装の一部を実行しません。彼らは、単に定義されたモジュールをインポートし、問題の名前をロードするだけで、それを解除します。関数を検索する名前空間がない場合(__main__のグローバルをのグローバルと結びついていない独自のカスタムdictに置き換えた場合、__main__.f(修飾名f)は0ではないため、pickleはできません。 __main__のグローバルには存在しません。

+0

コンパイル/ execでモジュールを定義する方法はありますか? – zjffdu

+0

@zjffdu:インポートされたモジュールのグローバルを 'exec'に渡すと、そこに定義されているように動作します。たとえば、 'import os'のように、' fs'が実際に 'os'モジュールで定義され、' os.f'という修飾名で定義されるため、 'exec(a、vars(os))'が機能します。だから、それを節約することができました( 'fs'という名前の関数を' os'モジュールに付け加えていない人は、それを解読することができませんでした)。 – ShadowRanger

関連する問題