web-dev-qa-db-ja.com

Picklerでの__reduce__の正確な使用法は何ですか

ピクル可能にするためには、クラスが__reduce__メソッドを上書きし、文字列またはタプルを返す必要があることを知っています。

この機能はどのように機能しますか? __reduce__の正確な使用法は何ですか?いつ使用されますか?

36
oyjh

私はこれを説明するのに一生懸命かどうか見ます。

オブジェクトをpickle化しようとすると、シリアル化できないプロパティがいくつかあります。たとえば、開いているファイルハンドルこの場合、pickleはオブジェクトの処理方法を認識せず、エラーをスローします。

これらのタイプのオブジェクトをクラス内でネイティブに直接処理する方法をpickleモジュールに伝えることができます。単一のプロパティを持つオブジェクトの例を作成してみましょう。開いているファイルハンドル:

_import pickle

class test(object):
    def __init__(self, file_path = 'test1234567890.txt'):
        self.some_file_i_have_opened = open(file_path, 'wb')  # An open file in write mode.

my_test = test()
# Now, watch what happens when we try to pickle this object:
pickle.dumps(my_test)
_

それは失敗し、トレースバックを与える必要があります:

_Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  --- snip snip a lot of lines ---
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle file objects
_

ただし、testclassに___reduce___メソッドを定義した場合、pickleはこのオブジェクトをシリアル化する方法を知っていたはずです。

_import pickle

class test(object):
    def __init__(self, file_path = 'test1234567890.txt'):
        self._file_name_we_opened = file_path  # Used later in __reduce__
        self.some_file_i_have_opened = open(self._file_name_we_opened, 'wb')  # An open file in write mode.
    def __reduce__(self):
        return (self.__class__, (self._file_name_we_opened, ))  # we return a Tuple of class_name to call, and optional parameters to pass when re-creating

my_test = test()
saved_object = pickle.dumps(my_test)
print repr(saved_object)  # Just print the representation of the string of the object, because it contains newlines.
_

これにより、次のような結果が得られます。_"c__main__\ntest\np0\n(S'test1234567890.txt'\np1\ntp2\nRp3\n."_。これは、開いているファイルハンドルでオブジェクトを再作成するために使用できます。

_print vars(pickle.loads(saved_object))
_

通常、大きな混乱は___reduce___が返すオブジェクトのタイプにあります。あなたはドキュメントのページでどのタイプのオブジェクトreduceが返すべきかについてもう少し読むことができます: https://docs.python。 org/3/library/pickle.html#object。reduce ですが、通常、少なくとも2つのタプルが必要です。

  1. 呼び出す空のオブジェクトクラス。この場合、_self.__class___
  2. クラスコンストラクターに渡す引数のタプル。この場合、それは単一の文字列であり、これは開くファイルへのパスです。

他にもオプションのアイテムがありますが、それらについてはすべてドキュメントで読む必要があります。

お役に立てば幸いです。

60
VooDooNOFX