Как правильно сортировать экземпляр 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()
Ответы
Ответ 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')
→ это вызовет ошибку