python - No se puede encurtir por defecto.
pickle defaultdict (7)
Actualmente estoy haciendo algo similar a la pregunta poser, sin embargo, estoy usando una subclase de defaultdict que tiene una función miembro que se usa como default_factory. Para que mi código funcione correctamente (solicité que la función se definiera en tiempo de ejecución), simplemente agregué algo de código para preparar el objeto para el decapado.
En lugar de:
...
pickle.dump(dict, file)
...
Yo uso esto:
....
factory = dict.default_factory
dict.default_factory = None
pickle.dump(dict, file)
dict.default_factory = factory
...
Este no es el código exacto que utilicé, ya que mi árbol es un objeto que crea instancias del mismo tipo de árbol a la que se solicitan los índices (así que uso una función de miembro recursivo para realizar las operaciones de pickle pre / post), pero este patrón también responde la pregunta
Tengo un defaultdict que se ve así:
dict1 = defaultdict(lambda: defaultdict(int))
El problema es que no puedo decaparlo usando cPickle. Una de las soluciones que encontré aquí es usar una función de nivel de módulo en lugar de un lambda. Mi pregunta es, ¿qué es la función de nivel de módulo? ¿Cómo puedo usar el diccionario con cPickle?
Además de la explicación de Martijn :
Una función de nivel de módulo es una función que se define a nivel de módulo, lo que significa que no es un método de instancia de una clase, no está anidada dentro de otra función y es una función "real" con un nombre, no una función lambda .
Por lo tanto, para elegir su valor defaultdict
, defaultdict
con una función de nivel de módulo en lugar de una función lambda:
def dd():
return defaultdict(int)
dict1 = defaultdict(dd) # dd is a module-level function
de lo que puedes esconderlo
tmp = pickle.dumps(dict1) # no exception
new = pickle.loads(tmp)
Para hacer esto, simplemente escriba el código que quería escribir. Usaría dill , que puede serializar lambdas y defaultdicts. El eneldo puede serializar casi cualquier cosa en python.
>>> import dill
>>> from collections import defaultdict
>>>
>>> dict1 = defaultdict(lambda: defaultdict(int))
>>> pdict1 = dill.dumps(dict1)
>>> _dict1 = dill.loads(pdict1)
>>> _dict1
defaultdict(<function <lambda> at 0x10b31b398>, {})
Pickle desea almacenar todos los atributos de la instancia, y las instancias default
almacenan una referencia a la opción de llamada default
. Pickle recurre sobre cada atributo de instancia.
Pickle no puede manejar lambdas; pickle solo maneja datos, no código, y las lambdas contienen código. Las funciones pueden ser decapadas, pero al igual que las definiciones de clase solo si la función se puede importar . Se puede importar una función definida a nivel de módulo. Pickle simplemente almacena una cadena en ese caso, la ''ruta'' completa de la función que se importará y se referenciará cuando se vuelva a seleccionar.
Si no te importa preservar el tipo de sentencia predeterminado, conviértelo:
fname = "file.pkl"
for value in nested_default_dict:
nested_default_dict[value] = dict(nested_default_dict[value])
my_dict = dict(nested_default_dict)
with open(fname, "wb") as f:
pickle.dump(my_dict, f) # Now this will work
Creo que esta es una excelente alternativa, ya que cuando estás decapando, el objeto probablemente se encuentra en su forma final ... Y, si realmente necesitas el tipo de punto predeterminado nuevamente, puedes convertirlo nuevamente después de haberlo seleccionado:
for value in my_dict:
my_dict[value] = defaultdict(type, my_dict[value])
nested_default_dict = defaultdict(type, my_dict)
Sin embargo, puede utilizar partial
para lograr esto:
>>> from collections import defaultdict
>>> from functools import partial
>>> pickle.loads(pickle.dumps(defaultdict(partial(defaultdict, int))))
defaultdict(<functools.partial object at 0x94dd16c>, {})
dict1 = defaultdict(lambda: defaultdict(int))
cPickle.dump(dict(dict1), file_handle)
trabajó para mi