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 можна успішно керувати логікою обробки даних з використанням вкладених структур, умовних перевірок та рекурсії. Вона не тільки робить код більш читабельним, завдяки їй можна також його значно спростити.
JetBrains випустила загальнодоступне останнє оновлення мови програмування Kotlin 2.3.0. Новий реліз має низку експериментальних функцій,…
Компанія OpenAI офіційно представила GPT-5.2-Codex — нову модель, яку названо «найдосконалішим інструментом для реальної розробки…
Міністерство фінансів України опублікувало законопроект про введення ПДВ для ФОП 1-3 груп. Прогнозується, що нові…
Google перенесла свій експериментальний конструктор міні-додатків Opal на платформу Gemini. Цей інструмент дозволяє створювати додатки…
Генерація коду за допомогою штучного інтелекту збільшує кількість проблем та їхню важливість. В аналізі 470…
Microsoft офіційно припиняє підтримку розширення для автодоповнення коду IntelliCode у редакторі Visual Studio Code. Замість…