Парсинг?

Расскажу вам о трюке, как можно обрабатывать (например, парсить) данные по какому-то ключу. Допустим, есть у нас поток с пакетами данных, которые необходимо принять и разложить по полочкам или какая-то другая задача, но наша проблема в том, что мы пишем код и понимаем, что сейчас у нас будет очень много if-ов и elif-ов и мы в них утонем.

Об оптимизации по скорости мы здесь не говорим, это просто пример.

class MyParser:

····def parse(self, some_chunk: dict) -> str:

········assert isinstance(some_chunk, dict)

········assert "action" in some_chunk

········assert "param" in some_chunk

········action, param = some_chunk["action"], some_chunk["param"]

········method = getattr(self, action, None)

········print(dir(method))

········res = method(some_chunk) if method else self.not_parsed(some_chunk)

········# Могли бы также вызвать method(param), если так будет удобней

········return res

····"""

····Здесь вся обработка полученных данных: парсинг или другое действие.

····"""

····def run(self, some_data: dict) -> str:

········"""

········Здесь действие для 'run', и так далее...

········"""

········...

········return "run processed"

····def stop(self, some_data: dict) -> str:

········...

········return "stop processed"

····def freeze(self, some_data: dict) -> str:

········...

········return "freeze processed"

····def restart(self, some_data: dict) -> str:

········...

········return "restart processed"

····def kill(self, some_data: dict) -> str:

········...

········return "kill processed"

····def info(self, some_data: dict) -> str:

········...

········return "info processed"

····def not_parsed(self, some_data):

········wtf_key = some_data["action"]

········raise RuntimeError(f"Undefined key found: {wtf_key}")

········# Или что-то другое, что должны сделать по умолчанию при

········# отсутствии обработчика такого ключа.

if __name__ == "__main__":

····data = [

········{"action": "run", "param": "some_0"},

········{"action": "stop", "param": "some_1"},

········{"action": "freeze", "param": "some_2"},

········{"action": "restart", "param": "some_3"},

········{"action": "kill", "param": "some_4"},

········{"action": "info", "param": "some_5"},

········{"action": "undefined", "param": "some_6"},

····]

····...

····mp = MyParser()

····for chunk in data:

········res = mp.parse(chunk)

········print(res)

Как видите, если у нас в классе есть обработчик для action, названный тем же именем, то мы его и вызываем. А если нет - особым образом обрабатываем такой случай.

Это кросспост из моего Telegram-канала "Не Ван Россум", где я прямо сейчас пишу сериал "101 вопрос про Python" с описанием подводных камней, неочевидностей и загвоздок.