Python 3.10 ضاف match/case من 4 سنين تقريبًا، ولحد دلوقتي أغلب الكود العربي اللي بنشوفه في GitHub لسه بيكتب سلاسل if/elif في حالات match فيها بيوفّر 30 سطر فعلًا. المقال يديك بالظبط امتى تستخدمه، وامتى يبقى مبالغة، بكود webhook حقيقي.
المشكلة باختصار
الـ if/elif في Python كويس لما عندك شرطين أو ثلاثة. المشكلة بتبدأ لما تيجي تـ parse استجابة API بشكل dict متشعّب، أو لما عندك 8 حالات لـ event types مختلفة. الكود بيبقى صعب القراءة، وبتنسى تتعامل مع حالة. match/case في Python 3.10+ بيحلّ ده، لكنه مش مجرد switch من C — الفرق الجوهري إنه structural، يعني بيقدر يفكّك (destructure) القيم وقت المطابقة نفسها.
الفرق الجوهري عن if/elif
match/case بيعمل حاجتين في نفس الوقت: مطابقة الشكل، واستخراج القيم. if/elif بيعمل المطابقة بس، الاستخراج بتعمله بإيدك في الجوّا. المثال ده على كائن webhook بيجي من Stripe بيوضح الفرق:
event = {"type": "payment.succeeded", "data": {"amount": 5000, "currency": "usd"}}
# الطريقة بـ if/elif (10 سطور وفيها تكرار get)
if event.get("type") == "payment.succeeded":
amount = event.get("data", {}).get("amount")
currency = event.get("data", {}).get("currency")
if isinstance(amount, int) and isinstance(currency, str):
process_payment(amount, currency)
elif event.get("type") == "payment.failed":
reason = event.get("data", {}).get("reason", "unknown")
log_failure(reason)
# الطريقة بـ match/case (5 سطور)
match event:
case {"type": "payment.succeeded", "data": {"amount": int(amount), "currency": str(currency)}}:
process_payment(amount, currency)
case {"type": "payment.failed", "data": {"reason": reason}}:
log_failure(reason)
case _:
log_unknown(event)
الفرق هنا مش جمالي. الـ pattern match بيتحقق من النوع (int, str) وبيستخرج القيمة في خطوة واحدة. لو الـ amount جاي string من webhook غلط، الـ case ده ما بيتطابقش، وبتنزل تلقائيًا للـ case _. الكود ده مش هيعمل crash بـ TypeError زي الـ if/elif.
أربعة أنماط هتستخدمها فعلًا
- Literal patterns — قيم ثابتة.
case 200: - Sequence patterns — قوائم وtuples مع unpacking.
case [first, *rest]: - Mapping patterns — dicts.
case {"status": "ok", "data": data}: