python - saving - Cómo agrupar correctamente una instancia de namedtuple
python pickle function (5)
Alternativamente, puede usar cloudpickle
o cloudpickle
para la serialización:
from collections import namedtuple
import cloudpickle
import dill
def dill_test(dynamic_names):
P = namedtuple(''P'', dynamic_names)
my_list = []
abe = P("abraham", "lincoln", "vampire", "hunter")
my_list.append(abe)
with open(''deleteme.cloudpickle'', ''wb'') as f:
cloudpickle.dump(abe, f)
with open(''deleteme.dill'', ''wb'') as f:
dill.dump(abe, f)
dill_test("one two three four")
Estoy aprendiendo a usar Pickle. Creé un objeto namedtuple, lo anexé a una lista y traté de reunir esa lista. Sin embargo, me sale el siguiente error:
pickle.PicklingError: Can''t pickle <class ''__main__.P''>: it''s not found as __main__.P
Descubrí que si ejecutaba el código sin envolverlo dentro de una función, funcionaba perfectamente. ¿Se necesita un paso adicional para encurtir un objeto cuando está envuelto dentro de una función?
Aquí está mi código:
from collections import namedtuple
import pickle
def pickle_test():
P = namedtuple("P", "one two three four")
my_list = []
abe = P("abraham", "lincoln", "vampire", "hunter")
my_list.append(abe)
f = open(''abe.pickle'', ''w'')
pickle.dump(abe, f)
f.close()
pickle_test()
Crea la tupla nombrada fuera de la función:
from collections import namedtuple
import pickle
P = namedtuple("P", "one two three four")
def pickle_test():
my_list = []
abe = P("abraham", "lincoln", "vampire", "hunter")
my_list.append(abe)
f = open(''abe.pickle'', ''w'')
pickle.dump(abe, f)
f.close()
pickle_test()
Ahora pickle
puede encontrarlo; es un módulo global ahora. Cuando se deshace, todo lo que tiene que hacer el módulo de pickle
es ubicar __main__.P
nuevamente. En su versión, P
es una función local , para la función pickle_test()
, y no es introspectible ni importable.
Es importante recordar que namedtuple()
es una fábrica de clases; le das parámetros y devuelve un objeto de clase para que crees instancias. pickle
solo almacena los datos contenidos en las instancias, más una referencia de cadena a la clase original para reconstruir las instancias nuevamente.
Después de que agregué mi pregunta como comentario a la respuesta principal, encontré una manera de resolver el problema de hacer una namedtuple
dinámicamente creada. Esto es necesario en mi caso porque estoy descubriendo los campos durante el tiempo de ejecución (después de una consulta DB).
Todo lo que hago es aplicar un parche a la namedtuple
con namedtuple
al namedtuple
efectivamente al módulo __main__
:
def _CreateNamedOnMain(*args):
import __main__
namedtupleClass = collections.namedtuple(*args)
setattr(__main__, namedtupleClass.__name__, namedtupleClass)
namedtupleClass.__module__ = "__main__"
return namedtupleClass
namedtuple
cuenta que el nombre namedtuple
(proporcionado por args
) puede sobrescribir a otro miembro en __main__
si no tienes cuidado.
El problema aquí es que los procesos secundarios no pueden importar la clase del objeto -en este caso, la clase P-, en el caso de un proyecto multi-modelo, la Clase P debería ser importable en cualquier lugar donde se use el proceso secundario.
una solución rápida es hacer que sea importable al afectarlo a globales ()
globals()["P"] = P
Encontré esta respuesta en otro hilo. Se trata de nombrar a la tupla nombrada. Esto funcionó para mí:
group_t = namedtuple(''group_t'', ''field1, field2'') # this will work
mismatched_group_t = namedtuple(''group_t'', ''field1, field2'') # this will throw the error