2009-08-28 9 views
6

(Usted puede leer this pregunta para algunos antecedentes)decapado con Gracia-degradantes en Python

me gustaría tener una manera degradante de gracia para el decapado de los objetos en Python.

Cuando el decapado de un objeto, vamos a llamarlo el objeto principal, a veces el Pickler lanza una excepción, ya que no puede conservar en vinagre una cierta sub-objeto del objeto principal. Por ejemplo, un error que he estado recibiendo mucho es "no puedo recortar objetos del módulo". Eso es porque estoy haciendo referencia a un módulo desde el objeto principal.

sé que puedo escribir un poco de algo para reemplazar ese módulo con una fachada que contendría los atributos del módulo, pero eso tendría sus propios problemas (1).

Así que lo que me gustaría es una función de decapado que reemplaza automáticamente los módulos (y cualesquiera otros objetos difíciles de salmuera) con fachadas que contienen sus atributos. Eso puede no producir un decapado perfecto, pero en muchos casos sería suficiente.

¿Hay algo como esto? ¿Alguien tiene una idea de cómo abordar esto?


(1) Una cuestión sería que el módulo puede estar haciendo referencia a otros módulos dentro de ella.

+1

Java Beans ... Python Pickles ... Me gustaría controlar a los nerds que se le ocurren cosas cursis –

Respuesta

0

¿Qué hay de lo siguiente, que es un envoltorio puede utilizar para envolver algunos módulos (puede ser cualquier módulo) en algo que es salmuera factible. A continuación, puede subclase el objeto Pickler para verificar si el objeto de destino es un módulo, y si es así, envuélvalo. ¿Esto logra lo que deseas?

class PickleableModuleWrapper(object): 
    def __init__(self, module): 
     # make a copy of the module's namespace in this instance 
     self.__dict__ = dict(module.__dict__) 
     # remove anything that's going to give us trouble during pickling 
     self.remove_unpickleable_attributes() 

    def remove_unpickleable_attributes(self): 
     for name, value in self.__dict__.items(): 
      try: 
       pickle.dumps(value) 
      except Exception: 
       del self.__dict__[name] 

import pickle 
p = pickle.dumps(PickleableModuleWrapper(pickle)) 
wrapped_mod = pickle.loads(p) 
0

Hmmm, algo como esto?

import sys 

attribList = dir(someobject) 
for attrib in attribList: 
    if(type(attrib) == type(sys)): #is a module 
     #put in a facade, either recursively list the module and do the same thing, or just put in something like str('modulename_module') 
    else: 
     #proceed with normal pickle 

Obviamente, esto iría en una extensión de la clase de la salmuera con un método volcado reimplementado ...

3

Puede decidir y ejecutar la forma en cualquier tipo previamente se unpicklable en vinagre y unpickled: véase la biblioteca estándar módulo copy_reg (renombrado a copyreg en Python 3. *).

Básicamente, debe proporcionar una función que, dada una instancia del tipo, la reduzca a una tupla, con el mismo protocolo que el método especial reduce (excepto que el método especial de reducción no toma argumentos, ya que siempre que se invoque directamente sobre el objeto, mientras que la función que proporcione tomará el objeto como único argumento).

Típicamente, la tupla que regrese tiene 2 artículos: un exigible, y una tupla de argumentos para transmitir a la misma. El invocable debe estar registrado como un "constructor seguro" o, de forma equivalente, tener un atributo __safe_for_unpickling__ con un valor verdadero. Esos ítems serán escabechados, y en el momento de desempate se llamará al llamable con los argumentos dados y debe devolver el objeto sin eliminar.

Por ejemplo, suponga que desea simplemente extraer los módulos por nombre, de modo que desatornillarlos solo significa volver a importarlos (es decir, suponga por simplicidad que no le importan los módulos modificados dinámicamente, los paquetes anidados, etc.) módulos simples de nivel superior).Entonces:

>>> import sys, pickle, copy_reg 
>>> def savemodule(module): 
... return __import__, (module.__name__,) 
... 
>>> copy_reg.pickle(type(sys), savemodule) 
>>> s = pickle.dumps(sys) 
>>> s 
"c__builtin__\n__import__\np0\n(S'sys'\np1\ntp2\nRp3\n." 
>>> z = pickle.loads(s) 
>>> z 
<module 'sys' (built-in)> 

estoy usando el formato ASCII pasada de moda de la salmuera para que s, la cadena que contiene la salmuera, es fácil de examinar: Instruye deserialiación para llamar a la función integrada de importación, con el cadena sys como su único argumento. Y z muestra que, de hecho, esto nos devuelve el módulo sys incorporado como resultado de la desaturación, según lo deseado.

Ahora, tendrás que hacer las cosas un poco más complejas que solo __import__ (tendrás que lidiar con guardar y restaurar cambios dinámicos, navegar por un espacio de nombres anidado, etc.), y así también tendrás que llama al copy_reg.constructor (pasando como argumento tu propia función que realiza este trabajo) antes de copy_reg la función de ahorro de módulo que devuelve tu otra función (y, si es una ejecución separada, también antes de deshacerte de las salmueras que hiciste usando dicha función). ¡Pero espero que estos casos simples ayuden a demostrar que realmente no hay nada que sea "intrínsecamente" complicado! -)

+0

@Alex Martelli: Cuando uso copy_reg.pickle, ¿cuál es el alcance en el cual este cambio será relevante? Quiero que las personas puedan importar mi trabajo sin que esto cambie los valores del sistema que puedan arruinar su programa. –

+0

'copy_reg' es global. Pero si no están actualmente encuadrando los módulos (lo cual es imposible por los valores predeterminados del sistema), no puede "arruinar su programa" para hacer que los módulos se puedan preparar. –

+0

@Alex Martelli: Pero si se toparan con el mismo problema y definieran el módulo de una manera diferente, tendríamos un problema. Creo en ser cortés y no cambiar el estado del sistema. Creo que cuando importes un módulo en Python no deberías tener que preocuparte de que se meta con los componentes globales de tu sistema, y ​​que es importante tener herramientas que te permitan evitar este tipo de "descortesía" en tus módulos. –

Cuestiones relacionadas