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 можна успішно керувати логікою обробки даних з використанням вкладених структур, умовних перевірок та рекурсії. Вона не тільки робить код більш читабельним, завдяки їй можна також його значно спростити.
Резиденти Дія.City сплатили до бюджету понад 8 млрд грн податків в І кварталі 2025 року.…
У Китаї закликають офісних працівників не працювати надто багато — держава сподівається, що вільний час…
Експерти звертають увагу на тривожну тенденцію: люди все частіше використовують ChatGPT, щоб визначити місцезнаходження, зображене…
Компанія JetBrains випустила нову версію мультимовного середовища розробки IntelliJ IDEA 2025.1. Оновлена IDE отримала численні…
Платформа обміну миттєвими повідомленнями Discord впроваджує функцію перевірки віку за допомогою сканування обличчя. Зараз вона…
Wikipedia намагається захистити себе від тисяч різноманітних ботів-скрейперів, які сканують дані цієї платформи для навчання…