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 <rep...@bugs.python.org>
<http://bugs.python.org/issue13520>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to