ตัวอย่างง่ายๆของการใช้ __setstate__ และ __getstate__


92

ฉันไม่รู้ว่า__setstate__และ __getstate__วิธีการทำอย่างไรจึงช่วยฉันด้วยตัวอย่างง่ายๆ


25
เอกสารยังไม่ค่อยดีนักในประเด็นนี้
Matt Luongo

คำตอบ:


80

นี่เป็นตัวอย่างที่ง่ายมากสำหรับงูหลามที่ควรเสริมเอกสารดอง

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)

9
เพื่อเสริมคำตอบนี้ให้พิมพ์ "ฉันถูกดอง" จากนั้น "ฉันไม่ได้รับค่าเหล่านี้: {'val': 4}" และ f_new.val คือ 12
timidpueo

45

ตัวอย่างน้อยที่สุด

สิ่งที่ออกมาของจะเข้าสู่getstate setstateไม่จำเป็นต้องเป็นคำสั่ง

สิ่งที่ออกมาของgetstateต้อง pickeable เช่นสร้างขึ้นจากพื้นฐานตัว -ins เช่นint, ,strlist

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

ค่าเริ่มต้น __setstate__

ค่าเริ่มต้น__setstate__ใช้เวลา a dict.

self.__dict__เป็นทางเลือกที่ดีเช่นเดียวกับในhttps://stackoverflow.com/a/1939384/895245แต่เราสามารถสร้างขึ้นมาเองเพื่อดูว่าเกิดอะไรขึ้น:

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

ค่าเริ่มต้น __getstate__

คล้ายคลึงกับ__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__ วัตถุไม่มี __dict__

ถ้าวัตถุมีแสดง__slots__ว่าไม่มี__dict__

หากคุณกำลังจะใช้ทั้งสองgetและsetstateวิธีเริ่มต้นคือ:

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__ เริ่มต้นรับและตั้งค่าคาดว่าจะมีทูเพิล

หากคุณต้องการนำค่าเริ่มต้นกลับมาใช้ใหม่__getstate__หรือ__setstate__คุณจะต้องส่งสิ่งต่อไปนี้เป็น:

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

ฉันไม่แน่ใจว่านี่คืออะไร

มรดก

ก่อนอื่นให้ดูว่าการดองทำงานตามค่าเริ่มต้น:

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

ประเพณีการสืบทอด __getstate__

หากไม่มี__slots__มันเป็นเรื่องง่ายเนื่องจาก__dict__for Dมี__dict__for Cดังนั้นเราจึงไม่จำเป็นต้องแตะCเลย:

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

มรดกและ __slots__

ด้วย__slots__เราจำเป็นต้องส่งต่อไปยังคลาสพื้นฐานและสามารถส่งต่อสิ่งรอบตัว:

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

น่าเสียดายที่ไม่สามารถใช้ค่าเริ่มต้น__getstate__และ__setstate__ฐานซ้ำได้: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQเราถูกบังคับให้กำหนด

ทดสอบกับ Python 2.7.12 GitHub อัปสตรี


10

วิธีการเหล่านี้ใช้สำหรับควบคุมวิธีการดองและไม่หยิบวัตถุโดยโมดูลดอง โดยปกติจะได้รับการจัดการโดยอัตโนมัติดังนั้นหากคุณไม่จำเป็นต้องลบล้างวิธีการดองหรือไม่ได้รับการคัดเลือกในชั้นเรียนคุณก็ไม่จำเป็นต้องกังวลเกี่ยวกับเรื่องนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.