拡張ライブラリに属するオブジェクトの酸洗サポートを実装したいと考えています。起動時に初期化される Service クラスのグローバル インスタンスがあります。これらのオブジェクトはすべて、いくつかの Service メソッド呼び出しの結果として生成され、本質的にそれに属しています。サービスは、それらをバイナリ バッファーにシリアル化する方法と、バッファーを逆シリアル化してオブジェクトに戻す方法を認識しています。
Pythons __ reduce__ が私の目的を果たすべきであるように思われました - 酸洗サポートを実装します。私は 1 つの実装を開始し、unpickler に問題があることに気付きました (__reduce__ によって返されると予想されるタプルの最初の要素)。この unpickle 関数は、入力バッファをオブジェクトに変換できるようにサービスのインスタンスを必要とします。この問題を説明するための擬似コードを次に示します。
class Service(object):
...
def pickleObject(self,obj):
# do serialization here and return buffer
...
def unpickleObject(self,buffer):
# do deserialization here and return new Object
...
class Object(object):
...
def __reduce__(self):
return self.service().unpickleObject, (self.service().pickleObject(self),)
タプルの最初の要素に注意してください。Python pickler はそれを好まない: それは instancemethod であり、pickle できないと言います。明らかに、pickler はルーチンを出力に格納しようとしており、Service インスタンスと関数名が必要ですが、これは望ましくありません。私はすべてのオブジェクトと一緒にサービスを保存したくありません(実際にはできません:サービスは選択できません)。pickle.load が呼び出される前にサービス インスタンスを作成し、どういうわけかそのインスタンスが unpickle 中に使用されるようにします。
ここで私は copy_reg モジュールにたどり着きました。繰り返しますが、私の問題を解決するはずです。このモジュールにより、pickler および unpickler ルーチンをタイプごとに動的に登録できます。これらは、後でこのタイプのオブジェクトに使用されることになっています。そこで、この登録を Service 構築に追加しました。
class Service(object):
...
def __init__(self):
...
import copy_reg
copy_reg( mymodule.Object, self.pickleObject, self.unpickleObject )
self.unpickleObject は、サービスを最初のパラメーターとして受け取り、バッファーを 2 番目のパラメーターとして受け取るバインドされたメソッドになりました。self.pickleObject も、pickle にサービスとオブジェクトを取得するバインドされたメソッドです。copy_reg では、pickleObject ルーチンがレデューサー セマンティックに従い、以前と同様のタプルを返す必要がありました。ここでまた問題が発生しました: 最初のタプル要素として何を返せばよいのでしょうか??
class Service(object):
...
def pickleObject(self,obj):
...
return self.unpickleObject, (self.serialize(obj),)
この形式では、pickle はインスタンスメソッドを pickle できないと再び文句を言います。私は None を試しました - それも好きではありません。私はそこにいくつかのダミー関数を入れました。これは機能します - つまり、シリアライゼーション フェーズは正常に完了しましたが、アンピクル中に、Service コンストラクターでタイプ mymodule.Object に登録した unpickler の代わりにこのダミー関数を呼び出します。
だから今、私は途方に暮れています。説明が長くなって申し訳ありません。この質問を数行で行う方法がわかりませんでした。私の質問は次のように要約できます。
- 個別に登録する必要がある場合、copy_reg セマンティックが pickleObject から unpickler ルーチンを返す必要があるのはなぜですか?
- unpickler ルーチンを登録するために copy_reg.constructor インターフェイスを好む理由はありますか?
- ストリーム内の unpickler ではなく、登録した unpickler を使用するように pickle を作成するにはどうすればよいですか?
- pickleObject の結果値として、タプルの最初の要素として何を返す必要がありますか? 「正しい」値はありますか?
- この全体に正しくアプローチできますか?異なる/より簡単な解決策はありますか?