|
13 | 13 | <h1>A Guide to Python's Magic Methods</h1> |
14 | 14 | <h3>Rafe Kettler</h3> |
15 | 15 | <p>Copyright © 2011 Rafe Kettler</p> |
16 | | -<p>Version 1.05</p> |
| 16 | +<p>Version 1.06</p> |
17 | 17 | <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> |
18 | 18 | <p><strong><a id="table" href="#table">Table of Contents</a></strong></p> |
19 | 19 | <dl> |
@@ -654,16 +654,52 @@ <h3>Pickling your own Objects</h3> |
654 | 654 | protocol has four optional methods for Python objects to customize how they act (it's a bit different for |
655 | 655 | C extensions, but that's not in our scope):</p> |
656 | 656 | <dl> |
657 | | -<dt><code>__getinitargs__()</code></dt> |
| 657 | +<dt><code>__getinitargs__(self)</code></dt> |
658 | 658 | <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> |
660 | 660 | <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> |
662 | 662 | <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> |
664 | 664 | <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> |
665 | 665 | </dl> |
666 | 666 | <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">'''Class to store a string and a changelog, and forget its value when</span> |
| 673 | +<span class="sd"> pickled.'''</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">'Changelog for Slate object:'</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">'</span><span class="si">%s</span><span class="se">\t</span><span class="s"> </span><span class="si">%s</span><span class="s">'</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 "blank slate" 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 | + |
667 | 703 | <h2><a id="conclusion" href="#conclusion">Conclusion</a></h2> |
668 | 704 | <p>The goal of this guide is to bring something to anyone that reads it, regardless of their experience with |
669 | 705 | Python or object-oriented programming. If you're just getting started with Python, you've gained valuable |
|
0 commit comments