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 можна успішно керувати логікою обробки даних з використанням вкладених структур, умовних перевірок та рекурсії. Вона не тільки робить код більш читабельним, завдяки їй можна також його значно спростити.
За підсумками вересня 2025 року обсяг IT-експорту з України становив $557 мільйонів, що на $17…
Спільне дослідження компаній Google і YouGov доводить, що через гаджети на базі Android рідше трапляються…
Українська ІТ-компанія FAVBET Tech увійшла до топ-5 найбільших платників податків серед резидентів «Дія.City» за підсумками…
Розробники TikTok переписали критично важливі Go API на Rust, що призвело до подвійного збільшення продуктивності…
OpenAI представила Aardvark — новий агент штучного інтелекту на базі GPT-5, який допомагає розробникам шукати…
Компанія Google оновила фреймворк ADK (Agent Development Kit). Вперше представлений у квітні цього року, ADK…