python programming language with example code on screen text vector illustration
Реліз Python 3.10, що вийшов у жовтні 2021 року, запропонував розробникам кілька цікавих змін, включно з pattern matching statement (оператор співставлення з шаблонами). Як запевняли автори PEP 622, на створення цієї пропозиції їх надихнув схожий синтаксис у мовах програмування Scala і Erlang.
Якщо ви ще не знайомі з pattern matching, то зараз у вас є хороша можливість дізнатися в цій статті, що виконує ця функція, як відбувається збіг, призначення та варіанти використання цього оператора в Python.
Відповідно до пояснень, викладених у PEP622, в коді Python іноді потрібно співставляти дані з типами, звертатися до них за індексом та застосовувати перевірку на тип. При цьому необхідно перевіряти не лише тип даних, але й їхнє число. А це призводить до того, що виникає велика кількість відгалужень if/else, які викликають функції isinstance, len і звертаються до елементів за індексом, атрибутом або ключем. Щоб уникнути подібних ускладнень та скоротити if/else, з’явився оператор Pattern matching.
До виходу Python 3.10 в його синтаксисі був простий і надійний спосіб порівняння значень з однією з безлічі можливих умов. Хоча в інших мовах такі фічі давно існували. Наприклад, у C і C++ є конструкція switch/case. Щось подібне є і в Rust.
Pattern matching у коді Python реалізується за допомогою конструкції match/case. Вона дозволяє співставляти вираз, структуру даних або тип шаблону. Простіше кажучи, Python перебирає всі варіанти шаблонів, доки знайде той шаблон, який відповідає виразу.
Важливо не плутати match/case та switch/case. Відмінності між ними полягають в тому, що pattern matching та його конструкція match/case — це не звичайний оператор для порівняння якоїсь змінної зі значеннями, а готовий механізм для співставлення даних, їхнього розпакування та управління потоком виконання.
Використовувати match/case можна в таких ситуаціях:
Тепер час настав для вивчення кількох прикладів, як цей оператор полегшує написання і роботу з кодом, роблячи його більш читабельним.
def day_type(day): match day: case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday": return "Weekday" case "Saturday" | "Sunday": return "Weekend" case _: return "Invalid day" print(day_type("Saturday")) # Output: Weekend
def describe_value(value): match value: case int(): return "This is an integer." case str(): return "This is a string." case list(): return "This is a list." case _: return "Unknown type." print(describe_value(42)) # Output: This is an integer.
def process_list(data): match data: case [a, b, c]: return f"List of three elements: {a}, {b}, {c}" case [a, b]: return f"List of two elements: {a}, {b}" case []: return "Empty list" case _: return "Different structure" print(process_list([1, 2, 3])) # Output: List of three elements: 1, 2, 3
def handle_request(request): match request: case {"method": "GET", "path": path}: return f"Handle GET request to {path}" case {"method": "POST", "path": path, "data": data}: return f"Handle POST request to {path} with data: {data}" case _: return "Unknown request format" print(handle_request({"method": "POST", "path": "/submit", "data": {"key": "value"}})) # Output: Handle POST request to /submit with data: {'key': 'value'}
def parse_response(response): match response: case {"status": 200, "data": {"id": id, "name": name}}: return f"Success! ID: {id}, Name: {name}" case {"status": 404}: return "Not Found" case {"status": 500, "error": error}: return f"Server Error: {error}" case _: return "Unknown response format" print(parse_response({"status": 200, "data": {"id": 123, "name": "Alice"}})) # Output: Success! ID: 123, Name: Alice
А зараз давайте перейдемо від простих прикладів коду до складних варіантів застосування match/case в Python. Фрагмент, який ви зараз побачите, демонструє аналіз складної структури даних та включає порівняння вкладених структур даних, використання умовних перевірок (guards) та вилучення значень.
Припустимо, у нас є система, яка призначена для обробки різних типів повідомлень у вигляді списків та вкладених словників. Всі повідомлення мають тип і здатні містити дані та метадані. Нам потрібно обробити всі типи повідомлень у різний спосіб, у тому числі з виконанням умовних перевірок.
def process_message(message): match message: case {"type": "user_action", "action": action, "details": {"user_id": user_id, "timestamp": timestamp}}: return f"User {user_id} performed {action} at {timestamp}" case {"type": "system_event", "event": event, "metadata": {"severity": severity}} if severity > 3: return f"Critical system event: {event} with severity {severity}" case {"type": "notification", "content": {"title": title, "message": msg}, "recipients": recipients}: if "admin" in recipients: return f"Admin notification: {title} - {msg}" else: return f"User notification: {title} - {msg}" case {"type": "batch", "messages": messages}: results = [process_message(msg) for msg in messages] return f"Batch processed with results: {results}" case _: return "Unknown message format" # Приклад повідомлень для обробки message1 = { "type": "user_action", "action": "login", "details": {"user_id": 42, "timestamp": "2024-08-22T14:00:00Z"} } message2 = { "type": "system_event", "event": "disk_failure", "metadata": {"severity": 5} } message3 = { "type": "notification", "content": {"title": "Maintenance", "message": "Scheduled maintenance at midnight"}, "recipients": ["admin", "user_123"] } message4 = { "type": "batch", "messages": [message1, message2, message3] } # Обробка повідомлень print(process_message(message1)) # Output: User 42 performed login at 2024-08-22T14:00:00Z print(process_message(message2)) # Output: Critical system event: disk_failure with severity 5 print(process_message(message3)) # Output: Admin notification: Maintenance - Scheduled maintenance at midnight print(process_message(message4)) # Output: Batch processed with results: [...]
Давайте розберемо, що ми бачимо у цьому коді.
Припустимо, нам доручили створити систему управління розумним будинком. Система отримує дані від датчиків, встановлених у різних приміщеннях. Вони передають інформацію про температуру, вологість, рівень освітлення та інші дані. Потім всі ці повідомлення надходять до пристроїв, які, швидше за все, мають різну структуру. Наше завдання полягає в тому, щоб ефективно обробити повідомлення від датчиків, використовуючи конструкцію match/case у Python.
Відповідно до умов задачі для кожного типу датчика потрібно:
def process_sensor_data(sensor_data): match sensor_data: # Повідомлення від датчика температури case {"type": "temperature", "value": temp, "unit": "C"} if temp > 30: return f"Warning: High temperature detected: {temp}°C. Turning on the AC." case {"type": "temperature", "value": temp, "unit": "C"}: return f"Temperature is normal: {temp}°C." # Повідомлення від датчика вологості case {"type": "humidity", "value": humidity, "unit": "%"} if humidity > 70: return f"Warning: High humidity detected: {humidity}%. Activating dehumidifier." case {"type": "humidity", "value": humidity, "unit": "%"}: return f"Humidity is normal: {humidity}%." # Повідомлення від датчика руху case {"type": "motion", "detected": True, "location": location}: return f"Motion detected in {location}. Turning on the lights." case {"type": "motion", "detected": False}: return "No motion detected." # Повідомлення від датчика освітлення case {"type": "light", "value": level, "unit": "lux"} if level < 50: return f"Low light level detected: {level} lux. Turning on the lights." case {"type": "light", "value": level, "unit": "lux"}: return f"Light level is sufficient: {level} lux." # Обробка невідомих типів повідомлень case _: return "Unknown sensor data received." # Приклади вхідних даних sensor_data1 = {"type": "temperature", "value": 32, "unit": "C"} sensor_data2 = {"type": "humidity", "value": 75, "unit": "%"} sensor_data3 = {"type": "motion", "detected": True, "location": "living room"} sensor_data4 = {"type": "light", "value": 30, "unit": "lux"} # Обробка даних print(process_sensor_data(sensor_data1)) # Output: Warning: High temperature detected: 32°C. Turning on the AC. print(process_sensor_data(sensor_data2)) # Output: Warning: High humidity detected: 75%. Activating dehumidifier. print(process_sensor_data(sensor_data3)) # Output: Motion detected in living room. Turning on the lights. print(process_sensor_data(sensor_data4)) # Output: Low light level detected: 30 lux. Turning on the lights.
Потрібно пояснити, що ми бачимо в цьому коді. Спочатку відбувається обробка повідомлень, отриманих від датчиків температури:
Обробка повідомлень від датчиків вологості:
Обробка повідомлень від датчиків руху:
Обробка даних від датчиків світла:
Обробка невідомих типів повідомлень:
Переваги використання match/case у цьому прикладі:
Як бачите, приклади демонструють, що за допомогою конструкції match/case можна успішно керувати логікою обробки даних з використанням вкладених структур, умовних перевірок та рекурсії. Вона не тільки робить код більш читабельним, завдяки їй можна також його значно спростити.
Компанія GlobalLogic заявила, що європейський регіон відтепер очолюватиме Юлія Штукатурова, повідомили в DOU. У GlobalLogic Юлія…
Флагманська LLM-модель OpenAI GPT-5 з'явиться вже в липні, як стверджують інсайдери. Модель матиме підтримку відео,…
Функція пам'яті ChatGPT, яка дозволяє звертатися до історії минулих розмов з чат-ботом, тепер стала доступною…
Після шести років обговорень та сотень пропозицій від ком'юніті команда розробників Go офіційно оголосила, що…
Команда Telegram випустила чергове велике оновлення. Адмінам каналів тепер можна надсилати особисті повідомлення, спростилося перемикання…
Таганський суд Москви ухвалив рішення про передачу у власність держави 100% уставного капіталу IT-компанії «Леста…