Skip to content

Commit 93bd617

Browse files
committed
Pickling example
1 parent 05b1e3b commit 93bd617

3 files changed

Lines changed: 115 additions & 9 deletions

File tree

magicmethods.html

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<h1>A Guide to Python's Magic Methods</h1>
1414
<h3>Rafe Kettler</h3>
1515
<p>Copyright &copy; 2011 Rafe Kettler</p>
16-
<p>Version 1.05</p>
16+
<p>Version 1.06</p>
1717
<p>The magic methods guide has a git repository at <a href="http://www.github.com/RafeKettler/magicmethods">http://www.github.com/RafeKettler/magicmethods</a>. Any issues can be reported there, along with comments, (or even contributions!).</p>
1818
<p><strong><a id="table" href="#table">Table of Contents</a></strong></p>
1919
<dl>
@@ -654,16 +654,52 @@ <h3>Pickling your own Objects</h3>
654654
protocol has four optional methods for Python objects to customize how they act (it's a bit different for
655655
C extensions, but that's not in our scope):</p>
656656
<dl>
657-
<dt><code>__getinitargs__()</code></dt>
657+
<dt><code>__getinitargs__(self)</code></dt>
658658
<dd>If you'd like for <code>__init__</code> to be called when your class is unpickled, you can define <code>__getinitargs__</code>, which should return a tuple of the arguments that you'd like to be passed to <code>__init__</code>. Note that this method will only work for old-style classes.</dd>
659-
<dt><code>__getnewargs__()</code></dt>
659+
<dt><code>__getnewargs__(self)</code></dt>
660660
<dd>For new-style classes, you can influence what arguments get passed to <code>__new__</code> upon unpickling. This method should also return a tuple of arguments that will then be passed to <code>__new__</code>.</dd>
661-
<dt><code>__getstate__()</code></dt>
661+
<dt><code>__getstate__(self)</code></dt>
662662
<dd>Instead of the object's <code>__dict__</code> attribute being stored, you can return a custom state to be stored when the object is pickled. That state will be used by <code>__setstate__</code> when the object is unpickled.</dd>
663-
<dt><code>__setstate__(state)</code></dt>
663+
<dt><code>__setstate__(self, state)</code></dt>
664664
<dd>When the object is unpickled, if <code>__setstate__</code> is defined the object's state will be passed to it instead of directly applied to the object's <code>__dict__</code>. This goes hand in hand with <code>__getstate__</code>: when both are defined, you can represent the object's pickled state however you want with whatever you want.</dd>
665665
</dl>
666666
<h3>An Example</h3>
667+
<p>Our example is a <code>Slate</code>, which remembers what its values have been and when those values were written to
668+
it. However, this particular slate goes blank each time it is pickled: the current value will not be saved.</p>
669+
<div class="codehilite"><pre><span class="kn">import</span> <span class="nn">time</span>
670+
671+
<span class="k">class</span> <span class="nc">Slate</span><span class="p">:</span>
672+
<span class="sd">&#39;&#39;&#39;Class to store a string and a changelog, and forget its value when</span>
673+
<span class="sd"> pickled.&#39;&#39;&#39;</span>
674+
675+
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
676+
<span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
677+
<span class="bp">self</span><span class="o">.</span><span class="n">last_change</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">asctime</span><span class="p">()</span>
678+
<span class="bp">self</span><span class="o">.</span><span class="n">history</span> <span class="o">=</span> <span class="p">{}</span>
679+
680+
<span class="k">def</span> <span class="nf">change</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">new_value</span><span class="p">):</span>
681+
<span class="c"># Change the value. Commit last value to history</span>
682+
<span class="bp">self</span><span class="o">.</span><span class="n">history</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">last_change</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span>
683+
<span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">new_value</span>
684+
<span class="bp">self</span><span class="o">.</span><span class="n">last_change</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">asctime</span><span class="p">()</span>
685+
686+
<span class="k">def</span> <span class="nf">print_changes</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
687+
<span class="k">print</span> <span class="s">&#39;Changelog for Slate object:&#39;</span>
688+
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">history</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
689+
<span class="k">print</span> <span class="s">&#39;</span><span class="si">%s</span><span class="se">\t</span><span class="s"> </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
690+
691+
<span class="k">def</span> <span class="nf">__getstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
692+
<span class="c"># Deliberately do not return self.value or self.last_change.</span>
693+
<span class="c"># We want to have a &quot;blank slate&quot; when we unpickle.</span>
694+
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">history</span>
695+
696+
<span class="k">def</span> <span class="nf">__setstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
697+
<span class="c"># Make self.history = state and last_change and value undefined</span>
698+
<span class="bp">self</span><span class="o">.</span><span class="n">history</span> <span class="o">=</span> <span class="n">state</span>
699+
<span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_change</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="bp">None</span>
700+
</pre></div>
701+
702+
667703
<h2><a id="conclusion" href="#conclusion">Conclusion</a></h2>
668704
<p>The goal of this guide is to bring something to anyone that reads it, regardless of their experience with
669705
Python or object-oriented programming. If you're just getting started with Python, you've gained valuable

magicmethods.mkd

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -769,20 +769,56 @@ Pickling isn't just for builtin types. It's for any class that follows the pickl
769769
protocol has four optional methods for Python objects to customize how they act (it's a bit different for
770770
C extensions, but that's not in our scope):
771771

772-
`__getinitargs__()`
772+
`__getinitargs__(self)`
773773
: If you'd like for `__init__` to be called when your class is unpickled, you can define `__getinitargs__`, which should return a tuple of the arguments that you'd like to be passed to `__init__`. Note that this method will only work for old-style classes.
774774

775-
`__getnewargs__()`
775+
`__getnewargs__(self)`
776776
: For new-style classes, you can influence what arguments get passed to `__new__` upon unpickling. This method should also return a tuple of arguments that will then be passed to `__new__`.
777777

778-
`__getstate__()`
778+
`__getstate__(self)`
779779
: Instead of the object's `__dict__` attribute being stored, you can return a custom state to be stored when the object is pickled. That state will be used by `__setstate__` when the object is unpickled.
780780

781-
`__setstate__(state)`
781+
`__setstate__(self, state)`
782782
: When the object is unpickled, if `__setstate__` is defined the object's state will be passed to it instead of directly applied to the object's `__dict__`. This goes hand in hand with `__getstate__`: when both are defined, you can represent the object's pickled state however you want with whatever you want.
783783

784784
###An Example###
785+
786+
Our example is a `Slate`, which remembers what its values have been and when those values were written to
787+
it. However, this particular slate goes blank each time it is pickled: the current value will not be saved.
788+
789+
:::python
790+
import time
791+
792+
class Slate:
793+
'''Class to store a string and a changelog, and forget its value when
794+
pickled.'''
795+
796+
def __init__(self, value):
797+
self.value = value
798+
self.last_change = time.asctime()
799+
self.history = {}
785800
801+
def change(self, new_value):
802+
# Change the value. Commit last value to history
803+
self.history[self.last_change] = self.value
804+
self.value = new_value
805+
self.last_change = time.asctime()
806+
807+
def print_changes(self):
808+
print 'Changelog for Slate object:'
809+
for k, v in self.history.items():
810+
print '%s\t %s' % (k, v)
811+
812+
def __getstate__(self):
813+
# Deliberately do not return self.value or self.last_change.
814+
# We want to have a "blank slate" when we unpickle.
815+
return self.history
816+
817+
def __setstate__(self, state):
818+
# Make self.history = state and last_change and value undefined
819+
self.history = state
820+
self.value, self.last_change = None, None
821+
786822
##<a id="conclusion" href="#conclusion">Conclusion</a>##
787823

788824
The goal of this guide is to bring something to anyone that reads it, regardless of their experience with

magicmethods.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,38 @@ class Distance(object):
162162
meters.'''
163163
meter = Meter()
164164
foot = Foot()
165+
166+
# Class to demo fine-tuning pickling
167+
import time
168+
169+
class Slate:
170+
'''Class to store a string and a changelog, and forget its value when
171+
pickled.'''
172+
173+
def __init__(self, value):
174+
self.value = value
175+
self.last_change = time.asctime()
176+
self.history = {}
177+
178+
def change(self, new_value):
179+
# Change the value. Commit last value to history
180+
self.history[self.last_change] = self.value
181+
self.value = new_value
182+
self.last_change = time.asctime()
183+
184+
def print_changes(self):
185+
print 'Changelog for Slate object:'
186+
for k, v in self.history.items():
187+
print '%s\t %s' % (k, v)
188+
189+
def __getstate__(self):
190+
# Deliberately do not return self.value or self.last_change.
191+
# We want to have a "blank slate" when we unpickle.
192+
return self.history
193+
194+
def __setstate__(self, state):
195+
# Make self.history = state and last_change and value undefined
196+
self.history = state
197+
self.value, self.last_change = None, None
198+
165199

0 commit comments

Comments
 (0)