2011-07-05 12 views
5

métodos de instancia no pueden automáticamente ser conservados en vinagre en tanto Python 2 o Python 3.¿Es esta la manera correcta de saltear métodos de instancia? Si es así, ¿por qué no está en Python 3?

necesito para conservar en vinagre métodos de instancia con Python 3 y I portados código ejemplo de Steven Bethard a Python 3:

import copyreg 
import types 

def _pickle_method(method): 
    func_name = method.__func__.__name__ 
    obj = method.__self__ 
    cls = method.__self__.__class__ 
    return _unpickle_method, (func_name, obj, cls) 

def _unpickle_method(func_name, obj, cls): 
    for cls in cls.mro(): 
     try: 
      func = cls.__dict__[func_name] 
     except KeyError: 
      pass 
     else: 
      break 
    return func.__get__(obj, cls) 

copyreg.pickle(types.MethodType, _pickle_method, _unpickle_method) 

¿Es esta método a prueba de tontos para métodos de instancia de decapado? ¿O pueden algunas cosas ir terriblemente mal? Lo he probado con algunas clases simuladas y todo parece funcionar.

Si nada puede salir mal, ¿por qué no es posible en Python 3 los métodos de instancia de pickle estándar?

+0

Debido a que todas las referencias deben ser accesibles a nivel mundial. http://www.velocityreviews.com/forums/t395502-why-cant-you-pickle-instancemethods.html –

+0

@Lennart Si miras el enlace, verás que encontré el mismo hilo yo mismo. Sin embargo, no explica muy bien cuál sería la diferencia real entre el decapado de un método y la función. Sé que también algunas funciones, como la función lambda, no pueden escamotearse, pero en ese caso se produce un error cuando no es posible. ¿Por qué no lo mismo para los métodos? –

Respuesta

0

No puedo reproducir el problema original en Python 3.5.0, consulte el siguiente ejemplo. Puede ser que sea digno de la comprobación de la versión más reciente para ver si simplemente funciona fuera de la caja :-)

import pickle 
import sys 

class Foo: 

    @staticmethod 
    def my_func(): 
     return 'Foo.my_func' 


class Bar: 
    pass 

if __name__ == '__main__': 
    if len(sys.argv) > 1 and sys.argv[1] == 'restore': 
     print('loading pickle') 
     with open('test.pickle', 'rb') as fp: 
      restored = pickle.load(fp) 
      print(restored.baz()) 
    else: 
     print('saving pickle') 
     b = Bar() 
     b.baz = Foo.my_func 

     with open('test.pickle', 'w+b') as fp: 
      p = pickle.dump(b, fp) 

(prueba) ~/prueba $ pitón test.py

ahorro salmuera

(prueba) ~/prueba $ pitón test.py restaurar

carga salmuera

Foo.my_func

0

Si desea conservar en vinagre instancias de clases (y los métodos de instancia), sólo tiene que utilizar dill ...

>>> import dill 
>>> 
>>> class Foo: 
... def bar(self, x): 
...  return self.y + x 
... def zap(self, y): 
...  self.y = y 
... y = 1 
... 
>>> f = Foo() 
>>> f.zap(4) 
>>> f.monty = 'python' 
>>> 
>>> _f = dill.dumps(f) 
>>> del Foo 
>>> del f 
>>> f = dill.loads(_f) 
>>> f.monty 
'python' 
>>> f.y 
4 
>>> 
>>> _b = dill.dumps(f.bar) 
>>> del f 
>>> bar = dill.loads(_b) 
>>> bar(4) 
8 
>>> 

dill obras cuando se elimina la clase de objeto, como se ve arriba ... por lo que también funciona si inicie una nueva sesión de python sin la clase definida, o si cambia la definición de la clase. dill incluso funciona cuando no tiene una instancia del objeto de clase o una instancia de clase disponible. Si quieres ver cómo hacerlo, mirar el código fuente dill: https://github.com/uqfoundation/dill

Véase también relacionada: https://stackoverflow.com/a/21345273/2379433

Cuestiones relacionadas