6

Python では、新しいスタイルの Python クラスに変換された後、古いスタイルの Python クラスとしてピクルされたオブジェクトをアンピクルすることは可能ですか? (つまり、異なる「クラス シグネチャ」を持つオブジェクト)。*

たとえば、いくつかのインスタンスが次のように保存されたとします。

class foo: # old style

クラスがオブジェクトから継承するように変更された後、さらにいくつかのオブジェクトがピクルされました。

class foo(object): # new style

1 つで 'ed されたオブジェクトは、同じスタイル クラスで 'edpickle.dumpできますpickle.loadが、どちらも両方をロードしません。pickle は継承によって戦略が変わると思います(object から継承するクラスは __reduce__ メソッドが自動定義されますが、継承しないクラスはそうではありません)。継承なしのコード (古いスタイルの定義) から継承のある古いスタイルの pickle をロードしようとすると、このSO questionで見られるのと同じ引数エラーが発生します。2 番目の引数は冗長ですが、それでも「クラス シグネチャ」と期待される引数が変更され、読み込みが妨げられます。これを解決するために、喜んで unpickler を書きますが、ドキュメントにある 2 つの別個のサブクラス化された unpickler が含まれる可能性があるのではないかと心配しています。... それぞれを正しく解凍する方法を知っていれば、それで問題ありません。

私の状況の背景を少し説明します... 私は TrialHandler クラスを使用して、行動心理学実験のボタンの押下と反応時間を保存および再読み込みしています。TrialHandler クラスをリファクタリングして、より抽象的な baseTrialHandler から継承するようにしましたが、その際に一時的にクラス シグネチャをobjectから継承するように変更しました。ただし、古い Trial_handler ファイルを unpickle できなかったため、元に戻しました。トライアル ハンドラーの両方のバージョンで実行された同じ実験のデータを確認したいので、同じスクリプトで両方の種類の保存されたログ ファイルを unpickle したいと考えています。

または、両方のオブジェクトを unpickle するカスタム unpickler を作成できない場合、それらをシリアル化する別の方法はありますか? yamlに直接ダンプしようとしましたが、とにかくクラスをyaml化できるものとして登録する必要があるようです。

特定のエラーに関する問題の完全な説明は、PsychoPy メーリング リストにあります。中間的な酸洗い、または Python 継承の詳細を説明するブログ投稿は、大歓迎です。私が見つけた最も近いものは、ピクリングが「単純なスタックベースの仮想マシン」として説明されている理由についての良い説明でした。

4

1 に答える 1

5

パーツを通過する:

  1. あなたの質問からアイデアを得ましたが、Pythonには「クラスシグネチャ」と呼ばれるものはありません
  2. Python 2プログラムで「オブジェクト」から継承しない場合は、エラーと見なす必要があります。オブジェクトから継承しないクラス-Python2.2(2000/2001年頃)で導入された新しいスタイルクラスの場合、下位互換性のために言語を維持した「古いスタイル」クラスとも呼ばれます-古いスタイルクラスの一貫性は大幅に低下しますそして今日のPythonをそのような素晴らしい言語にする多くの機能を欠いています。

それが邪魔にならないように:unpickleは、ピクルス時<module>.<class>にオブジェクトの属性に表示されるように、クラス修飾名に基づいてオブジェクトを逆シリアル化しようとします。__class__.__name__したがって、アンピクル例外(TypeErrorが発生する)で、使用可能なクラスを同じ名前で交換し、アンピクル操作を再試行するという素朴な方法が可能です。クラスは「オブジェクト」から継承する必要があります(より具体的には、 「タイプ」ベースのメタクラス)

私が言及した例に関しては、ただ何かを書いてください:

try:
    new_obj = pickle.load(data_stream)
except TypeError: # if you know this was caused due to the new version of "Foo" class:
    current_foo = foomodule.Foo
    foomodule.Foo = foomodule.OldFoo
    new_obj = pickle.load(data_stream)
    foomodule.Foo = current_foo
于 2012-04-06T03:49:33.890 に答える