Как лучше написать несколько предложений try для приведения строкового объекта json в класс данных? - PullRequest
0 голосов
/ 16 января 2020

У меня есть функция, которая получает несколько различных json строковых объектов с различной структурой и / или именами полей, например:

event = '{"userId": "TDQIQb2fQaORKvCyepDYoZgsoEE3", "profileIsCreated": true}'

или

event = '{"userId": "TDQIQb2fQaORKvCyepDYoZgsoEE3", "signUpFinished": true}'

И у меня есть классы данных примерно так:

from dataclasses import dataclass, field


@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(frozen=True)
class UserId:
    userId: str


@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(frozen=True)
class SignUpFinished(UserId):
    signUpFinished: bool


@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass(frozen=True)
class UserProfileCreated(UserId):
    profileIsCreated: bool

В настоящее время способ написания моей функции выглядит следующим образом:

def cast_event(event):
    user_details = None

    try:
        user_details = SignUpFinished.from_json(event)
    except KeyError:
        pass

    try:
        user_details = UserProfileCreated.from_json(event)
    except KeyError:
        pass

    if user_details:
        return "OK"
    else:
        return "UNHANDLED"

Проблема в том, что мне нужно обрабатывать все больше и больше событий, мой функция будет становиться все дольше и дольше, однако она будет делать только одно и то же.

Есть ли лучший способ достичь того, чего я хочу достичь?


Я проверил некоторые вопросов SO:

но они, похоже, не лучший способ добиться того, чего я хочу.

Ответы [ 2 ]

2 голосов
/ 16 января 2020

Хотя l oop подход работает для решения вашего вопроса в соответствии с заданным вопросом, было бы намного лучше, если бы вам не понадобился подход "грубой силы" для десериализации ваших данных в первую очередь. , Для этого вам понадобится поле, которое однозначно поможет вам определить, с какой структурой данных вы имеете дело. Например:

event = {'event': 'profile',
         'data': {'userId': 'TDQIQb2fQaORKvCyepDYoZgsoEE3', 'profileIsCreated': True}}

Здесь за событием 'profile' всегда будет следовать объект с клавишами 'userId' и 'profileIsCreated'. Это гарантия того, что ваши сообщения о событиях должны быть предоставлены, тогда их просто разобрать:

event_map = {
    'profile': UserProfileCreated,
    ...
}

return event_map[event['event']](**event['data'])

Обратите внимание, что здесь я пропускаю шаг разбора JSON. Сначала вам нужно проанализировать JSON, чтобы оценить его ключ event, поэтому использование dataclass_json, вероятно, излишне / бесполезно.

2 голосов
/ 16 января 2020

Так как каждый случай синтаксически одинаков, вы можете обрабатывать их в одном l oop. Выполните итерацию последовательности дел и от try до return; это автоматически продолжает пытаться более поздние случаи, пока один не удастся.

def cast_event(event):
    for case in (UserId , SignUpFinished, UserProfileCreated):
        try:
            return case.from_json(event)
        except KeyError:
            pass
    raise ValueError(f'not a valid event: {event}')
...