Обзор
Я хочу сериализовать сложные объекты. Это выглядит просто, но каждый шаг создает другую проблему.
В конце концов, другие программисты также должны иметь возможность создавать сложный объект, унаследованный от моего родительского объекта. И этот объект должен быть разборчивым, для Python 2.7 и Python3.x.
Я начал с простого объекта и успешно использовал pickle.dump
и pickle.load
.
Затем я создал несколько сложных объектов (похожих, но не идентичных), некоторые из которых можно сбрасывать, а некоторые не могут.
Отладка
Библиотека рассола знает, какие объекты можно мариновать или нет. Теоретически это означает, что pdb
может быть настроен для включения отладки pickle.
Альтернативные библиотеки сериализации
Мне нужна надежная сериализация, независимая от содержимого объекта. Поэтому я искал другие инструменты для сериализации:
- Cerealizer, который selftest не удался и, кажется, устарел.
- MessagePack, который недоступен для Python 3.
- Я попробовал JSON и получил ошибку:
builtins.TypeError: <lib.scan.Content object at 0x7f37f1e5da50> is not JSON serializable
- Я посмотрел на Маршала и Шелли, но все они относятся к Пике.
Копаем в использование рассола
Я прочитал Как проверить, является ли объект разборчивым, который не дал мне ответа.
Самое близкое, что я нашел, было Как найти источник ошибки в Python Pickle на массивном объекте
Я скорректировал это:
import pickle
if _future_.isPython3():
class MyPickler(pickle._Pickler):
def save(self, obj):
try:
pickle._Pickler.save(self, obj)
except:
print ('pick(3.x) {0} of type {1}'.format(obj, type(obj)))
else:
class MyPickler (pickle.Pickler):
def save(self, obj):
try:
pickle.Pickler.save(self, obj)
except:
print('pick(2.x)', obj, 'of type', type(obj))
Я вызываю этот код, используя:
def save(obj, file):
if platform.python_implementation() == 'CPython':
myPickler = MyPickler(file)
myPickler.save(obj)
Я ожидаю, что сохранение будет выполнено до тех пор, пока не будет создано исключение. Содержимое obj
напечатано, чтобы я мог точно видеть, где ошибка orcurs. Но результат:
pick(3.x) <class 'module'> of type <class 'type'>
pick(3.x) <class 'module'> of type <class 'type'>
pick(3.x) <class 'Struct'> of type <class 'type'>
pick(3.x) <class 'site.setquit.<locals>.Quitter'> of type <class 'type'>
pick(3.x) <class 'site.setquit.<locals>.Quitter'> of type <class 'type'>
pick(3.x) <class 'module'> of type <class 'type'>
pick(3.x) <class 'sys.int_info'> of type <class 'type'>
...
Это лишь небольшая часть результата. Я этого не понимаю. Это не помогает мне, какая деталь неправа для рассола. И как это решить.
Я видел: http://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled, но это не очень помогает, если я не могу определить, какая строка в моем коде не может быть маринована.
Код в моем сложном объекте работает как ожидающий, в конце работает сгенерированный код как:
sys.modules['unum']
Но при травлении кажется, что "модуль" не читается, как ожидалось.
Попытка решения
Некоторые предпосылки, чтобы понять, что я имею в виду. У меня были программы, которые работали, и внезапно не сработали. Это может быть обновление или другой ресурс изменений. Программы, которые работают для других, а не для меня и наоборот.
Это общая проблема, поэтому я хочу разработать программу для проверки всех видов ресурсов. Количество различных видов ресурсов огромно. Поэтому у меня есть один класс родительских объектов со всем общим поведением. И как минимум, возможный класс подробностей для конкретных ресурсов.
Это выполняется в моих дочерних классах ресурсов.
Эти ресурсы должны быть проверены с различными версиями f.e. Python 2.7 или Python 3.3 Если вы используете Python 2.7.5, ресурс действителен, если требуется Python 2.7 и выше. Таким образом, проверка должна быть немного больше, чем равное значение. Это указано как один оператор в пользовательском файле конфигурации. Для каждой программы есть определенный файл конфигурации, который должен быть как можно меньше. Один ресурс проверяется с помощью одного оператора в файле конфигурации.
Общий класс составляет около 98% кода. Конкретные ресурсы и конфигурация составляют около 2% кода. Таким образом, очень легко добавить новые ресурсы для проверки и новые файлы конфигурации для новых программ.
Эти дочерние ресурсы:
class R_Sys(r_base.R_Base):
'''
doc : http://docs.python.org/3/library/sys.html#module-sys
sys.modules returns only a list of imported module
statement :
sys.modules['psutil'] # may return false (installed but not imported
but the statements :
import psutil
sys.modules['psutil'] # will return true, now psutil is imported
'''
allowed_names = ('modules', 'path', 'builtin_module_names', 'stdin')
allowed_keys_in_dict_config = ('name',)
allowed_operators = ("R_NONE", "=", 'installed') # installed only for modules
class_group = 'Sys'
module_used = sys
def __init__(self, check_type, group, name):
super(R_Sys, self).__init__(check_type, group, name)
вызываемый этим оператором config:
sc.analyse(r.R_Sys, c.ct('DETECT'), dict(name='path'))
может быть успешно протравлено. Но с командой config:
sc.analyse(r.R_Sys, c.ct('DETECT'),
dict(name='modules', tuplename='unum') )
он не работает.
Это означает, что, по моему мнению, 98% основной код должен быть в порядке, иначе первый оператор также потерпит неудачу.
В дочернем классе есть атрибуты класса. Они должны функционировать должным образом. И снова в первом вызове дамп выполняется хорошо. Я еще не делал нагрузки.