pickle and instancemethod objects

Discussion in 'Python' started by Steven Bethard, Sep 13, 2006.

  1. I'd like to be able to pickle instancemethod objects mainly because I
    want to be able to delay a call like ``foo(spam, badger)`` by dumping
    ``foo``, ``spam`` and ``badger`` to disk and loading them again later.
    Sometimes the callable ``foo`` is actually a bound method, e.g.
    ``bar.baz``, but in such cases, pickle doesn't work by default because
    it doesn't know how to pickle/unpickle instancemethod objects.

    I was thinking of doing something like::

    >>> def pickle_instancemethod(method):

    .... func_name = method.im_func.__name__
    .... cls = method.im_class
    .... obj = method.im_self
    .... return unpickle_instancemethod, (func_name, cls, obj)
    ....
    >>> def unpickle_instancemethod(func_name, cls, obj):

    .... if obj is None:
    .... return getattr(cls, func_name)
    .... else:
    .... return getattr(obj, func_name)
    ....
    >>> class C(object):

    .... def __init__(self, foo, bar):
    .... self.foo = foo
    .... self.bar = bar
    .... def baz(self):
    .... return self.foo, self.bar
    ....
    >>> copy_reg.pickle(type(C.baz),

    .... pickle_instancemethod,
    .... unpickle_instancemethod)

    This seems to basically do the right thing on the few simple things I've
    tried::

    >>> c = C(42, 'badger')
    >>> new_c_baz = pickle.loads(pickle.dumps(c.baz))
    >>> new_c_baz()

    (42, 'badger')
    >>> new_C_baz = pickle.loads(pickle.dumps(C.baz))
    >>> new_C_baz(C('eki', 'fekang'))

    ('eki', 'fekang')

    Does this approach seem sound? Am I going to run into some weird
    problems doing it this way?

    Thanks,

    STeVe
     
    Steven Bethard, Sep 13, 2006
    #1
    1. Advertising

  2. Steven Bethard schrieb:
    > Does this approach seem sound? Am I going to run into some weird
    > problems doing it this way?


    It's good, but I think rebuilding the object through
    new.instancemethod should be even better.

    py> class A:
    .... def f(self):print "A"
    ....
    py> class B(A):
    .... def f(self):print "B"
    ....
    py> b=B()
    py> b.f
    <bound method B.f of <__main__.B instance at 0xa7d728cc>>
    py> x = new.instancemethod(A.__dict__['f'], b, A)
    py> x
    <bound method A.f of <__main__.B instance at 0xa7d728cc>>
    py> x()
    A
    py> b.f()
    B
    py> x.im_func.__name__,x.im_class,x.im_self
    ('f', <class __main__.A at 0xa7d7002c>, <__main__.B instance at 0xa7d728cc>)

    On unpickling x, you'ld get x.(B.f), not x.(A.f) with your
    approach.

    Not sure it matters much.

    Regards,
    Martin
     
    =?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=, Sep 13, 2006
    #2
    1. Advertising

  3. Martin v. Löwis wrote:
    > Steven Bethard schrieb:
    >> Does this approach seem sound? Am I going to run into some weird
    >> problems doing it this way?

    >
    > It's good, but I think rebuilding the object through
    > new.instancemethod should be even better.
    >
    > py> class A:
    > ... def f(self):print "A"
    > ...
    > py> class B(A):
    > ... def f(self):print "B"
    > ...
    > py> b=B()
    > py> b.f
    > <bound method B.f of <__main__.B instance at 0xa7d728cc>>
    > py> x = new.instancemethod(A.__dict__['f'], b, A)
    > py> x
    > <bound method A.f of <__main__.B instance at 0xa7d728cc>>
    > py> x()
    > A
    > py> b.f()
    > B
    > py> x.im_func.__name__,x.im_class,x.im_self
    > ('f', <class __main__.A at 0xa7d7002c>, <__main__.B instance at 0xa7d728cc>)
    >
    > On unpickling x, you'ld get x.(B.f), not x.(A.f) with your
    > approach.
    >
    > Not sure it matters much.


    Probably doesn't matter for my particular use, but it certainly wouldn't
    hurt to do it the careful way. Thanks.

    Is new.instancemethod basically equivalent to calling __get__? That is,
    would the following two unpickle_instancemethod functions do the same thing?

    def unpickle_instancemethod(func_name, cls, obj):
    return cls.__dict__[func_name].__get__(obj, cls)

    def unpickle_instancemethod(func_name, cls, obj):
    return new.instancemethod(cls.__dict__[func_name], obj, cls)

    Thanks again,

    STeVe
     
    Steven Bethard, Sep 13, 2006
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rim
    Replies:
    7
    Views:
    360
    Terry Reedy
    Jul 28, 2003
  2. Martin Miller
    Replies:
    1
    Views:
    370
    Peter Hansen
    Mar 12, 2005
  3. a pickle's pickle

    , Aug 2, 2005, in forum: Python
    Replies:
    4
    Views:
    407
  4. Jim Lewis

    can't pickle instancemethod objects

    Jim Lewis, Jul 9, 2006, in forum: Python
    Replies:
    6
    Views:
    1,316
    Jim Lewis
    Jul 9, 2006
  5. Michele Simionato
    Replies:
    2
    Views:
    1,936
    Michele Simionato
    May 23, 2008
Loading...

Share This Page