Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>A new feature was added to Python 2.7.3 that allows for <em>dynamically</em> created classes to be pickled. See <a href="http://bugs.python.org/issue7689" rel="nofollow">issue 7689</a>:</p> <blockquote> <p>Currently, it's impossible to use the usual pickle mechanisms to pickle a dynamically created class, even if the user requests a different pickling mechanism via copy_reg. The attached patch makes this customization possible by simply transposing two blocks of code. </p> </blockquote> <p>and</p> <blockquote> <p>The copy_reg module exists to handle custom pickling of objects, which is exactly what's needed here. However, the code from <strike><a href="http://bugs.python.org/issue494904" rel="nofollow">#494904</a></strike> that checks for instances of a metaclass does this *just before* it looks at the copy_reg dispatch table. The patches just reorder these tests in pickle.py and cPickle.c, so that one can register a custom pickler for instances of a metaclass. </p> </blockquote> <p>And from the <a href="http://hg.python.org/cpython/file/d46c1973d3c4/Misc/NEWS#l328" rel="nofollow">2.7.3 changelog</a>:</p> <blockquote> <p>Issue #7689: Allow pickling of dynamically created classes when their metaclass is registered with copy_reg. Patch by Nicolas M. Thiéry and Craig Citro.</p> </blockquote> <p>The only way around this for Python 2.6 is to port the <code>pickle.py</code> module over to that version. You could try to just bundle the 2.7.3 <code>pickle.py</code> module with 2.6, as a pure Python implementation it should Just Work.</p> <p>Alternatively, monkey-patch the <code>pickle.Pickler.save</code> method:</p> <pre><code>from copy_reg import dispatch_table from types import TypeType, StringType, TupleType from pickle import Pickler, PicklingError def pickler_save(self, obj): # Check for persistent id (defined by a subclass) pid = self.persistent_id(obj) if pid: self.save_pers(pid) return # Check the memo x = self.memo.get(id(obj)) if x: self.write(self.get(x[0])) return # Check the type dispatch table t = type(obj) f = self.dispatch.get(t) if f: f(self, obj) # Call unbound method with explicit self return # Check copy_reg.dispatch_table reduce = dispatch_table.get(t) if reduce: rv = reduce(obj) else: # Check for a class with a custom metaclass; treat as regular class try: issc = issubclass(t, TypeType) except TypeError: # t is not a class (old Boost; see SF #502085) issc = 0 if issc: self.save_global(obj) return # Check for a __reduce_ex__ method, fall back to __reduce__ reduce = getattr(obj, "__reduce_ex__", None) if reduce: rv = reduce(self.proto) else: reduce = getattr(obj, "__reduce__", None) if reduce: rv = reduce() else: raise PicklingError("Can't pickle %r object: %r" % (t.__name__, obj)) # Check for string returned by reduce(), meaning "save as global" if type(rv) is StringType: self.save_global(obj, rv) return # Assert that reduce() returned a tuple if type(rv) is not TupleType: raise PicklingError("%s must return string or tuple" % reduce) # Assert that it returned an appropriately sized tuple l = len(rv) if not (2 &lt;= l &lt;= 5): raise PicklingError("Tuple returned by %s must have " "two to five elements" % reduce) # Save the reduce() output and finally memoize the object self.save_reduce(obj=obj, *rv) Pickler.save = pickler_save </code></pre> <p>With the above monkey patch, your example works on Python 2.6.8:</p> <pre><code>&gt;&gt;&gt; pickle.dumps(B) Hey there 'c__main__\nB\np0\n.' </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload