pickle and instancemethod objects

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steven Bethard

    #1

    pickle and instancemethod objects

    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_instance method(method):
    .... func_name = method.im_func. __name__
    .... cls = method.im_class
    .... obj = method.im_self
    .... return unpickle_instan cemethod, (func_name, cls, obj)
    ....
    >>def unpickle_instan cemethod(func_n ame, 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.pick le(type(C.baz),
    .... pickle_instance method,
    .... unpickle_instan cemethod)

    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(pi ckle.dumps(c.ba z))
    >>new_c_baz()
    (42, 'badger')
    >>new_C_baz = pickle.loads(pi ckle.dumps(C.ba z))
    >>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
  • Martin v. Löwis

    #2
    Re: pickle and instancemethod objects

    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.instancemet hod should be even better.

    pyclass A:
    .... def f(self):print "A"
    ....
    pyclass B(A):
    .... def f(self):print "B"
    ....
    pyb=B()
    pyb.f
    <bound method B.f of <__main__.B instance at 0xa7d728cc>>
    pyx = new.instancemet hod(A.__dict__['f'], b, A)
    pyx
    <bound method A.f of <__main__.B instance at 0xa7d728cc>>
    pyx()
    A
    pyb.f()
    B
    pyx.im_func.__n ame__,x.im_clas s,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

    Comment

    • Steven Bethard

      #3
      Re: pickle and instancemethod objects

      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.instancemet hod should be even better.
      >
      pyclass A:
      ... def f(self):print "A"
      ...
      pyclass B(A):
      ... def f(self):print "B"
      ...
      pyb=B()
      pyb.f
      <bound method B.f of <__main__.B instance at 0xa7d728cc>>
      pyx = new.instancemet hod(A.__dict__['f'], b, A)
      pyx
      <bound method A.f of <__main__.B instance at 0xa7d728cc>>
      pyx()
      A
      pyb.f()
      B
      pyx.im_func.__n ame__,x.im_clas s,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.instancemet hod basically equivalent to calling __get__? That is,
      would the following two unpickle_instan cemethod functions do the same thing?

      def unpickle_instan cemethod(func_n ame, cls, obj):
      return cls.__dict__[func_name].__get__(obj, cls)

      def unpickle_instan cemethod(func_n ame, cls, obj):
      return new.instancemet hod(cls.__dict_ _[func_name], obj, cls)

      Thanks again,

      STeVe

      Comment

      Working...