Estoy aprendiendo a usar la vinagreta. He creado un namedtuple objeto, al que se anexa a una lista, y trató de pepinillo esa lista. Sin embargo, me sale el siguiente error:

pickle.PicklingError: Can't pickle <class '__main__.P'>: it's not found as __main__.P

He encontrado que si me encontré con el código sin envolver dentro de una función, funciona perfectamente. Hay un paso adicional necesario para pickle un objeto cuando se ajusta 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()
  • Por desgracia, pepinillo no parece funcionar bien con namedtuples.
  • pickle maneja namedtuple clases muy bien, las clases se definen en función de espacio de nombres local no tanto.
  • posibles duplicados de Python: no se Puede pickle tipo X, atributo de error de búsqueda
  • Esta pregunta se la hicieron a/respondida hace un año 🙂
  • Que no afecta si es un duplicado y ahora las preguntas están ligados el uno al otro en la barra lateral, lo que es útil. El comentario es que no se entiende como una crítica, se genera automáticamente cuando el marcado.
  • Ninguno tomado. Sólo pensé que era gracioso. Cuestión de la vinculación es de hecho muy útil 🙂
  • Hay un problema similar. Si el tipo de variable y el tipo de cadena que se utiliza en el constructor no son iguales, pepinillo también fallará. por ejemplo, P = namedtuple("Q", "one two three four")
  • Para la posteridad: que el error también se produce si el typename argumento para namedtuple no coincide con el nombre de la clase devuelto por namedtuple. Ver: stackoverflow.com/a/28149627/3396951

5 Comentarios

  1. 65

    Crear el nombre de la tupla 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 encontrar; se trata de un módulo global ahora. Cuando unpickling, todos los pickle módulo tiene que hacer es encontrar __main__.P de nuevo. En su versión, P es un local, a la pickle_test() función, y que no es introspectable o importables.

    Es importante recordar que namedtuple() es una fábrica de clase; se dan los parámetros y devuelve un objeto de la clase para crear instancias de. pickle sólo almacena la datos contenida en las instancias, además de una cadena de referencias a la clase original para reconstruir las instancias de nuevo.

    • Excelente! Gracias.
    • Así, lo que si voy a crear la namedtuple dinámicamente porque no sé los campos hasta el tiempo de ejecución? Aún hay una manera de saltarse este problema? Yo intenté crear otro método fuera de la clase, pero que no funcionó.
    • Asignar a su módulo globals (uso globals() para obtener un mapeo) en el mismo nombre, y pickle puede encontrar todavía.
  2. 8

    Después he añadido mi pregunta como un comentario a la principal respuesta que he encontrado una manera de resolver el problema de cómo hacer una creados dinámicamente namedtuple pickle-poder. Esto es necesario en mi caso, porque estoy averiguando sus campos sólo en tiempo de ejecución (después de una DB de consulta).

    Todo lo que hago es mono parche la namedtuple de manera eficaz para mover a la __main__ módulo:

    def _CreateNamedOnMain(*args):
        import __main__
        namedtupleClass = collections.namedtuple(*args)
        setattr(__main__, namedtupleClass.__name__, namedtupleClass)
        namedtupleClass.__module__ = "__main__"
        return namedtupleClass

    Cuenta que el namedtuple nombre (el cual es proporcionado por args) podría sobrescribir otro miembro en __main__ si no tienes cuidado.

    • Simplemente póngalo en globals() lugar: globals()[namedtupleClass.__name__] = namedtupleClass. Entonces no es no hay necesidad para establecer el __module__.
    • Cuando traté de globals()[namedtupleClass.__name__] = namedtupleClass de hecho me permiten pickle mi objeto, pero cuando traté de unpickle no tenía la namedtupleClass que necesitaba. Mi consejo es que sólo tiene que utilizar un diccionario hasta hacer de pepinillo lo suficientemente inteligente como para hacer esto.
    • Bien hecho @Chuim simple y funciona 🙂
  3. 5

    He encontrado esta respuesta en otro hilo. Esto es todo acerca de la nomenclatura del nombre de la tupla. 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
    • La primera fila no resuelve el problema para mí
  4. 3

    Como alternativa, puede utilizar cloudpickle o eneldo 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")
  5. 0

    El problema aquí es que el niño los procesos no son capaces de importar la clase del objeto -en este caso, la clase P-, en el caso de una multi-modelo de proyecto de la Clase de P debe ser importables en cualquier lugar del niño en el proceso de acostumbrarse

    una rápida solución es que se pueden importar que afectan a globals()

    globals()["P"] = P

Dejar respuesta

Please enter your comment!
Please enter your name here