with saving open how python python-2.7 pickle namedtuple

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