Сериализация пользовательских классов с помощью JSON в Python 3
У меня возникают проблемы, когда JSON пытается декодировать мой сериализованный пользовательский класс с информацией о классе, закодированной в dict. Я постараюсь предоставить как можно больше информации, поэтому, пожалуйста, миритесь с длинным постом.
Я использую отличный учебник, представленный здесь в качестве ссылки. Я имею в виду раздел, в котором подробно пишется кодирование / декодирование для ваших собственных классов.
Моя структура пакета-модуля частично выглядит следующим образом:
+--- PyDev Project
+-- src
+-- astar
| +-- __init__.py
| +-- astar.py
+-- common
| +-- __init__.py
| +-- service.py
| +-- graph.py
| +-- vertex.py
Каждый из этих модулей имеет свой класс (ы). Я сериализую объект класса Service в модуле common.service. Это в основном для использования через соединение Pyro.
Код сериализации:
def convert_to_builtin_type(obj):
print('default(', repr(obj), ')')
# Convert objects to a dictionary of their representation
d = { '__class__':obj.__class__.__name__,
'__module__':obj.__module__,
}
d.update(obj.__dict__)
return d
Код десериализации:
def dict_to_object(self, d):
if '__class__' in d:
class_name = d.pop('__class__')
module_name = d.pop('__module__')
# module = __import__(module_name)
module = import_module(module_name)
print('MODULE:', module)
class_ = getattr(module, class_name)
print('CLASS:', class_)
args = dict( (key.encode('ascii'), value) for key, value in d.items())
print('INSTANCE ARGS:', args)
inst = class_(**args)
else:
inst = d
return inst
Проблема возникает во время десериализации. Значения локальной переменной:
class_ = <module 'common.Service' from path-to-file.py>
class_name = 'Service'
module = <module 'common' from path-to-__init__.py>
module_name = 'common.Service'
Причина этого заключается в том, что класс_ возвращает значение package.module, а не имя класса внутри этого модуля. Технически, класс_ должен содержать common.service.Service, который является фактическим классом. Из-за этого последний оператор inst = class(** args) _ завершается с ошибкой "TypeError: модуль не вызывается".
Я знаю, что import или importlib.import_module оба импортируют этот модуль верхнего уровня, но в моем случае, как мне добраться до класса внутри модуля второго уровня? Технически, второй уровень - это модуль, а первый уровень - это пакет, поэтому мне нужен класс в pkg.module, к которому я не могу добраться.
Я надеюсь, что вопрос имел смысл и показал достаточно исследований. У меня есть больше информации, если это нужно уточнить.
РЕДАКТИРОВАТЬ: Проблема решена с предложением пользователя.
def dict_to_object(self, d):
if '__class__' in d:
class_name = d.pop('__class__')
module_name = d.pop('__module__')
# module = __import__(module_name)
__import__(module_name)
module = sys.modules[module_name]
print('MODULE:', module)
class_ = getattr(module, class_name)
print('CLASS:', class_)
args = dict((key, value) for key, value in d.items())
print('INSTANCE ARGS:', args)
inst = class_(**args)
else:
inst = d
return inst
1 ответ
Идеи:
Возможно, проблема в этой строке:
import_module(module_name)
пересмотреть аргументы, которые вы передаете этой функции.
зная сериализатор рассола, он делает следующее вместо
import_module
import sys __import__(module_name) module = sys.modules[module_name]
В Python 3 попробуйте также
obj.__class__.__qualname__
, он включает в себя имя модуля и классы вложенности.class X: class Y: pass # __qualname__ includes X.Y
Было бы хорошо, если бы вы опубликовали рабочий код позже, потому что это может быть проблемой для многих людей.