Подтвердить что ты не робот

Как правильно сортировать экземпляр namedtuple

Я изучаю, как использовать рассол. Я создал объект namedtuple, добавил его в список и попытался рассортировать этот список. Однако я получаю следующую ошибку:

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

Я обнаружил, что если я запустил код, не обернув его внутри функции, он отлично работает. Есть ли дополнительный шаг, необходимый для рассортирования объекта при обертывании внутри функции?

Вот мой код:

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()
4b9b3361

Ответ 1

Создайте именованный кортеж вне функции:

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()

Теперь pickle может найти его; теперь это модуль глобальный. При рассыпке всем модулем pickle необходимо снова найти __main__.P. В вашей версии P является локальной, для функции pickle_test(), и это не является интроспективным или импортируемым.

Важно помнить, что namedtuple() - это класс factory; вы даете ему параметры и возвращает объект класса для создания экземпляров. pickle хранит только данные, содержащиеся в экземплярах, плюс ссылку на исходный класс для восстановления экземпляров снова.

Ответ 2

После того, как я добавил свой вопрос в качестве комментария к основному ответу, я нашел способ решить проблему создания динамически созданного namedtuple разборки. Это необходимо в моем случае, потому что я обнаруживаю поля во время выполнения (после запроса БД).

Все, что я делаю, - это обезглавить патч namedtuple, эффективно перемещая его в модуль __main__:

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

Помните, что имя namedtuple (которое предоставляется args) может перезаписать другой член в __main__, если вы не будете осторожны.

Ответ 3

В качестве альтернативы вы можете использовать cloudpickle или dill для сериализации:

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")

Ответ 4

Я нашел этот ответ в другом потоке и все об именовании названного кортежа. Это сработало для меня:

mhawke solutio to - Запись и чтение namedtuple в файл в python

group_t = namedtuple('group_t', 'field1, field2') → это будет работать

mismatched_group_t = namedtuple('group_t', 'field1, field2') → это вызовет ошибку