Message168820
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 |
|
Date |
User |
Action |
Args |
2012-08-21 23:16:04 | sbt | set | recipients:
+ sbt, pitrou, vstinner, alexandre.vassalotti, lukasz.langa |
2012-08-21 23:16:04 | sbt | set | messageid: <1345590964.14.0.139572634752.issue13520@psf.upfronthosting.co.za> |
2012-08-21 23:16:03 | sbt | link | issue13520 messages |
2012-08-21 23:16:03 | sbt | create | |
|