Contoh sederhana penggunaan __setstate__ dan __getstate__

92

Saya tidak tahu apa yang dilakukan __setstate__dan __getstate__metode, jadi bantu saya dengan contoh sederhana.

zjm1126
sumber
25
Dokumentasinya tidak terlalu bagus dalam hal ini.
Matt Luongo

Jawaban:

80

Berikut adalah contoh yang sangat sederhana untuk Python yang harus melengkapi dokumen acar .

class Foo(object):
  def __init__(self, val=2):
     self.val = val
  def __getstate__(self):
     print("I'm being pickled")
     self.val *= 2
     return self.__dict__
  def __setstate__(self, d):
     print("I'm being unpickled with these values: " + repr(d))
     self.__dict__ = d
     self.val *= 3

import pickle
f = Foo()
f_data = pickle.dumps(f)
f_new = pickle.loads(f_data)
BrainCore
sumber
9
Untuk melengkapi jawaban ini, tertera "Saya sedang dibuat acar", lalu "Saya sedang tidak dicabut dengan nilai-nilai ini: {'val': 4}", dan f_new.val adalah 12.
timidpueo
45

Contoh minimal

Apapun yang keluar getstate, masuk ke dalam setstate. Ini tidak perlu menjadi dikt.

Apa pun yang datang dari getstateharus pickeable, misalnya terdiri dari dasar built-in seperti int, str, list.

class C(object):
    def __init__(self, i):
        self.i = i
    def __getstate__(self):
        return self.i
    def __setstate__(self, i):
        self.i = i
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

Default __setstate__

Defaultnya __setstate__adalah dict.

self.__dict__adalah pilihan yang baik seperti di https://stackoverflow.com/a/1939384/895245 , tetapi kita dapat membuatnya sendiri untuk melihat dengan lebih baik apa yang sedang terjadi:

class C(object):
    def __init__(self, i):
        self.i = i
    def __getstate__(self):
        return {'i': self.i}
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

Default __getstate__

Analog dengan __setstate__.

class C(object):
    def __init__(self, i):
        self.i = i
    def __setstate__(self, d):
        self.i = d['i']
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

__slots__ benda tidak punya __dict__

Jika benda tersebut memiliki __slots__, maka ia tidak memiliki__dict__

Jika Anda akan menerapkan keduanya getdan setstate, cara default-ishnya adalah:

class C(object):
    __slots__ = 'i'
    def __init__(self, i):
        self.i = i
    def __getsate__(self):
        return { slot: getattr(self, slot) for slot in self.__slots__ }
    def __setsate__(self, d):
        for slot in d:
            setattr(self, slot, d[slot])
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

__slots__ get dan set default mengharapkan tupel

Jika Anda ingin menggunakan kembali default __getstate__atau __setstate__, Anda harus melewatkan tupel sebagai:

class C(object):
    __slots__ = 'i'
    def __init__(self, i):
        self.i = i
    def __getsate__(self):
        return (None, { slot: getattr(self, slot) for slot in self.__slots__ })
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

Saya tidak yakin untuk apa ini.

Warisan

Pertama, lihat bahwa pengawetan berfungsi secara default:

class C(object):
    def __init__(self, i):
        self.i = i
class D(C):
    def __init__(self, i, j):
        super(D, self).__init__(i)
        self.j = j
d = pickle.loads(pickle.dumps(D(1, 2), -1))
assert d.i == 1
assert d.j == 2

Kebiasaan warisan __getstate__

Tanpanya __slots__mudah, karena __dict__for Dberisi __dict__for C, jadi kita tidak perlu menyentuh Csama sekali:

class C(object):
    def __init__(self, i):
        self.i = i
class D(C):
    def __init__(self, i, j):
        super(D, self).__init__(i)
        self.j = j
    def __getstate__(self):
        return self.__dict__
    def __setstate__(self, d):
        self.__dict__ = d
d = pickle.loads(pickle.dumps(D(1, 2), -1))
assert d.i == 1
assert d.j == 2

Warisan dan __slots__

Dengan __slots__, kita perlu meneruskan ke kelas dasar, dan dapat mengirimkan tupel di sekitar:

class C(object):
    __slots__ = 'i'
    def __init__(self, i):
        self.i = i
    def __getstate__(self):
        return { slot: getattr(self, slot) for slot in C.__slots__ }
    def __setstate__(self, d):
        for slot in d:
            setattr(self, slot, d[slot])

class D(C):
    __slots__ = 'j'
    def __init__(self, i, j):
        super(D, self).__init__(i)
        self.j = j
    def __getstate__(self):
        return (
            C.__getstate__(self),
            { slot: getattr(self, slot) for slot in self.__slots__ }
        )
    def __setstate__(self, ds):
        C.__setstate__(self, ds[0])
        d = ds[1]
        for slot in d:
            setattr(self, slot, d[slot])

d = pickle.loads(pickle.dumps(D(1, 2), -1))
assert d.i == 1
assert d.j == 2

Sayangnya, tidak mungkin menggunakan kembali default __getstate__dan __setstate__basis: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ kami terpaksa mendefinisikannya.

Diuji pada Python 2.7.12. GitHub upstream .

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
10

Metode ini digunakan untuk mengontrol bagaimana objek diawetkan dan dilepas oleh modul acar . Ini biasanya ditangani secara otomatis, jadi kecuali Anda perlu menimpa bagaimana kelas diawetkan atau diurai, Anda tidak perlu khawatir tentang itu.

Pär Wieslander
sumber