Richard Oudkerk added the comment:
There is a cute way to use operator.attrgetter to produce backwards compatible
pickles using the qualname:
import pickle, copyreg, operator, sys, pickletools, types
class AttrGetter(object):
def __init__(self, name):
self.name = name
def __call__(self): # pretend to be callable
raise RuntimeError
def __reduce__(self):
return operator.attrgetter, (self.name,)
def reduce_by_qualname(obj):
mod = sys.modules[obj.__module__]
first, rest = obj.__qualname__.split('.', 1)
firstobj = getattr(mod, first)
assert operator.attrgetter(rest)(firstobj) is obj
return AttrGetter(rest), (firstobj,)
# FunctionType defaults to save_global but uses fallback if it fails
copyreg.pickle(types.FunctionType, reduce_by_qualname)
class A(object):
class B(object):
class C(object):
@staticmethod
def foo():
print("foo foo foo")
def bar():
print("bar bar bar")
for obj in [A.B.C.foo, bar]:
data = pickle.dumps(obj, 2)
pickletools.dis(data)
func = pickle.loads(data)
assert func is obj
func()
This produces
0: \x80 PROTO 2
2: c GLOBAL 'operator attrgetter'
23: q BINPUT 0
25: X BINUNICODE 'B.C.foo'
37: q BINPUT 1
39: \x85 TUPLE1
40: q BINPUT 2
42: R REDUCE
43: q BINPUT 3
45: c GLOBAL '__main__ A'
57: q BINPUT 4
59: \x85 TUPLE1
60: q BINPUT 5
62: R REDUCE
63: q BINPUT 6
65: . STOP
highest protocol among opcodes = 2
foo foo foo
0: \x80 PROTO 2
2: c GLOBAL '__main__ bar'
16: q BINPUT 0
18: . STOP
highest protocol among opcodes = 2
bar bar bar
----------
_______________________________________
Python tracker <[email protected]>
<http://bugs.python.org/issue13520>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com