4

pickle を使用してカスタム クラスをダンプしようとしています。このクラスは gtk.ListStore からサブクラス化されました。これにより、特定のデータを簡単に保存し、gtk を使用して表示できるようになりました。これは、ここに示すように再現できます。

import gtk
import pickle
import os

class foo(gtk.ListStore):
    pass

if __name__=='__main__':
    x = foo(str)
    with open(os.path.expandvars('%userprofile%\\temp.txt'),'w') as f:
        pickle.dump(x,f)

私が試した解決策は__getstate__、クラスに関数を追加することでした。私がドキュメンテーションを理解している限り、これは pickle に優先され、ListStore をシリアル化しようとしなくなりますが、これは実行できません。ただし、オブジェクトをピクルしようとすると、pickle.dump から同じエラーが発生します。エラーは次のように再現できます。

import gtk
import pickle
import os

class foo(gtk.ListStore):
    def __getstate__(self):
        return 'bar'

if __name__=='__main__':
    x = foo(str)
    with open(os.path.expandvars('%userprofile%\\temp.txt'),'w') as f:
        pickle.dump(x,f)

いずれの場合も、pickle.dump は「ListStore オブジェクトをピクルできません」という TypeError を発生させます。print ステートメントを使用して、__getstate__pickle.dump を使用したときに関数が実行されることを確認しました。ドキュメントから次に何をすべきかについてのヒントが見当たらないので、少し困っています。助言がありますか?

4

2 に答える 2

1

この方法を使用すると、目的に合わせて pickle の代わりに json を使用することもできます。

のような「ピクルできない型」をピクルするために採用する必要がある手順を示す簡単な作業例を次に示しますgtk.ListStore。基本的に、いくつかのことを行う必要があります。

  1. __reduce__インスタンスの再構築に必要な関数と引数を返すものを定義します。
  2. ListStore の列の型を決定します。このメソッドself.get_column_type(0)は Gtype を返すため、これを対応する Python 型にマップし直す必要があります。これは演習として残しました。私の例では、値の最初の行から列の型を取得するためにハックを採用しました。
  3. 関数_new_fooはインスタンスを再構築する必要があります。

例:

import gtk, os, pickle

def _new_foo(cls, coltypes, rows):
    inst = cls.__new__(cls)
    inst.__init__(*coltypes)
    for row in rows:
        inst.append(row)
    return inst

class foo(gtk.ListStore):

    def __reduce__(self):
        rows = [list(row) for row in self]
        # hack - to be correct you'll really need to use 
        # `self.get_column_type` and map it back to Python's 
        # corresponding type.
        coltypes = [type(c) for c in rows[0]]
        return _new_foo, (self.__class__, coltypes, rows)

x = foo(str, int)
x.append(['foo', 1])
x.append(['bar', 2])

s = pickle.dumps(x)

y = pickle.loads(s)
print list(y[0])
print list(y[1])

出力:

['foo', 1]
['bar', 2]
于 2011-05-11T19:41:29.117 に答える
0

object をサブクラス化すると、object.__reduce__が呼び出しを処理し__getstate__ます。これは のサブクラスであるgtk.ListStoreため、 のデフォルトの実装は、最初にオブジェクト__reduce__を再構築するためにデータをピクルしようとしgtk.ListStore、次に を呼び出します__getstate__が、 はgtk.ListStoreピクルできないため、クラスをピクルすることを拒否します。の代わりに__reduce__andを実装しようとすると、問題は解決するはずです。__reduce_ex____getstate__

>>> class Foo(gtk.ListStore):
...     def __init__(self, *args):
...             super(Foo, self).__init__(*args)
...             self._args = args
...     def __reduce_ex__(self, proto=None):
...             return type(self), self._args, self.__getstate__()
...     def __getstate__(self):
...             return 'foo'
...     def __setstate__(self, state):
...             print state
... 
>>> x = Foo(str)
>>> pickle.loads(pickle.dumps(x))
foo
<Foo object at 0x18be1e0 (__main__+Foo-v3 at 0x194bd90)>

さらに、 などの他のシリアライザーを検討することもできますjson。そこでは、カスタム クラスを自分でシリアル化する方法を定義することで、シリアル化プロセスを完全に制御できます。さらに、デフォルトでは、セキュリティの問題はありませんpickle

于 2011-05-11T19:25:21.477 に答える