Каковы наилучшие методы объединения определений схемы зефира и объектно-ориентированного программирования в Python?

Предположим, что простая схема определена в marshmallow.

class AddressSchema(Schema):
    street=fields.String(required=True)
    city=fields.String(required=True)
    country=fields.String(default='USA')

class PersonSchema(Schema):
    name=fields.String(required=True)
    address=fields.Nested(AddressSchema())

Вариант использования здесь — приложения, работающие с объектами в памяти, и сериализация/десериализация в JSON, то есть без базы данных SQL.

Используя стандартную библиотеку json, я могу анализировать объекты JSON, которые соответствуют этой схеме, и получать доступ к объектам способом, например person1['address']['city'], но использование подверженных опечаткам строк в подробном синтаксисе несколько неудовлетворительно.

ОО модель ручной работы

Я мог бы определить параллельную объектно-ориентированную модель и аннотировать свою схему декораторами @post_load, например:

class Address(object):
    def __init__(self, street, city, country='USA'):
        self.street=street
        self.city=city
        self.country=country

class Person(object):
    def __init__(self, street, city=None):
        self.street=street
        self.city=city

Но повторение не очень приятно (и я даже не включил описания в схему).

Нет ОО модели

Возможно, явная объектно-ориентированная модель мало что дает — это базовые средства доступа к данным, никакого поведения. Я мог бы получить немного синтаксического сахара, используя jsobject, чтобы написать, например, person1.address.city. Но и это кажется не совсем правильным. Как разработчик, у меня нет явного API-интерфейса класса python, с которым можно было бы проконсультироваться, чтобы определить, какие поля использовать, я могу ссылаться на схему зефира, но это кажется очень косвенным.

Генерация кода

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

Пользователям кода не нужно было бы знать, что использовался подход codegen — все было бы там с явным API, с документами, видимыми вместе с остальным кодом в readthedocs и т. д.

Динамические классы

Другим подходом могут быть динамические классы, производные от определений зефира. Опять же, насколько я могу судить, такой библиотеки нет (хотя диапазон подходов динамической генерации классов в python впечатляет, возможно, я что-то упустил). Возможно, это не принесет вам многого по сравнению с подходом jsobjects, но могут быть некоторые преимущества - можно было бы переплести это с некоторым явным кодом с определенным поведением. Недостатком динамического подхода является то, что в мире Python явное предпочтение отдается неявному.

Что самое питоническое?

Отсутствие библиотек здесь означает, что я либо чего-то не нахожу, либо не смотрю на это с подходящей питонической точки зрения. Я рад внести свой вклад в pypi, но прежде чем добавить еще одну мета-OO-библиотеку, я хотел убедиться, что я провел здесь должную осмотрительность.


person Chris Mungall    schedule 21.08.2017    source источник
comment
Я задал аналогичный вопрос в stackoverflow.com/questions/45831888 /   -  person Teyras    schedule 29.08.2017
comment
То, что наиболее пифонично, по крайней мере, находится на грани субъективности :) Я проголосовал за вопрос, поскольку он правильно сформулирован и ясен, но также голосую за закрытие.   -  person BartoszKP    schedule 17.04.2018
comment
Взгляните на классы данных Python 3.7.   -  person Jacques de Hooge    schedule 03.09.2018
comment
Вы можете использовать pypi.org/project/marshmallow-dataclass и не определять свою схему вручную.   -  person lovasoa    schedule 05.02.2019


Ответы (1)


Ваш вопрос довольно расплывчатый, и таким будет мой ответ, и довольно субъективный, я надеюсь, что все в порядке. Я просто какой-то чувак, который провел день, читая варианты сериализации в python.

Я думаю, что Marshmallow принципиально непитоновский, и нет хорошего способа его использовать, я не собираюсь его использовать. Я приведу то, что для меня является двумя определяющими примерами.

  1. У вас есть класс, который имеет в качестве поля смешанный список других объектов. Это python, так что вам разрешено это делать. В зефире вы не можете справиться с этим естественно или аккуратно. Есть очень естественное решение, заключающееся в том, чтобы записать/поднять список классов, используя их зарегистрированные сериализаторы. Но в Marshmallow вам придется написать свой собственный код и изменить сериализатор каждого возможного класса, чтобы убедиться, что он зарегистрирован в чем-то, что вы передаете во вложенную функцию. Он не регистрирует сериализаторы для классов, вам придется добавить это. Описание проблемы.
  2. Вы хотите сериализовать смешанный (буквальный) словарь строк в неизвестные классы. Это почти то же самое, что и выше, вам придется реализовать это самостоятельно. Кроме того, вам придется написать сериализатор/de самостоятельно для каждого примитива, для которого вы хотите это сделать. Они написали код для примитивов в виде полей, но не схем, что для меня не является включенными батареями или одним из очевидных способов.

Общие библиотеки сериализации — своего рода глубокая кроличья нора, потому что то, о чем вы действительно говорите, требует элементов системы типов, синтаксического анализатора и алгоритма обхода графа за один раз. Marshmallow по умолчанию не выполняет рекурсивный анализ, поэтому он не выполняет пункт (2). В пункте (1) (отчасти из-за 2) требуется либо обширный взлом, либо требуется, чтобы вы приняли систему типов, подобную Java (все имеет известный, перечисляемый тип).

Вы спрашивали об общих библиотеках сериализации, мне показалась интересной библиотека camel и сообщение в блоге о ней. Для рассола есть мощное расширение под названием dill и миксин, который обрабатывает управление версиями

person zimablue    schedule 15.11.2018