6

拡張ライブラリに属する​​オブジェクトの酸洗サポートを実装したいと考えています。起動時に初期化される 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 の代わりにこのダミー関数を呼び出します。

だから今、私は途方に暮れています。説明が長くなって申し訳ありません。この質問を数行で行う方法がわかりませんでした。私の質問は次のように要約できます。

  1. 個別に登録する必要がある場合、copy_reg セマンティックが pickleObject から unpickler ルーチンを返す必要があるのはなぜですか?
  2. unpickler ルーチンを登録するために copy_reg.constructor インターフェイスを好む理由はありますか?
  3. ストリーム内の unpickler ではなく、登録した unpickler を使用するように pickle を作成するにはどうすればよいですか?
  4. pickleObject の結果値として、タプルの最初の要素として何を返す必要がありますか? 「正しい」値はありますか?
  5. この全体に正しくアプローチできますか?異なる/より簡単な解決策はありますか?
4

1 に答える 1