لو كاتب 14 سطر if event["type"] == "..." علشان توزّع رسائل webhook على handlers مختلفة، Python بترجع نفس النتيجة في 8 أسطر بـ match statement، وبأداء أسرع 3.7 مرة. هنا بالظبط ليه، إمتى يستحق، وإمتى تفضل تسيب الـ if القديم.
Pattern Matching في Python: مش مجرد switch جديد
المشكلة باختصار
في API بيستقبل webhook events من Stripe، الكود التقليدي بيتحوّل بسرعة لطابور if/elif طويل: "لو نوع الـ event كذا وعنده الحقل دا والقيمة الفلانية، اعمل الإجراء كذا". الكود ده بيكبر من 8 لـ 40 سطر في 3 شهور، وكل مضيف جديد بيلمس نفس الـ function. الـ PR review بيبقى كابوس، والـ unit tests بتدور حوالين نفس الـ branching المتكرر.
الـ match statement اللي دخل Python 3.10 (PEP 634، 636) مش switch أحسن. هو آلية مطابقة على الشكل الهيكلي للبيانات: نوع، عدد عناصر، حقول داخلية، وقيم ثوابت — كلهم مع بعض في pattern واحد. الفرق ده هو اللي بيخلّيه يحلّ مشكلة الـ webhook router في 8 أسطر بدل 40.
مثال للمبتدئ: مكتب البريد اللي بيفرز الطرود
تخيّل موظف في مكتب بريد قدامه سير ناقل بيمرّ عليه طرود مختلفة. مع كل طرد بيشوف ثلاث حاجات: شكله (ظرف، صندوق، أنبوبة)، عليه ختم أحمر ولا أزرق، ووزنه. عنده 6 مسارات توزيع، وكل مسار بيتحدد بمزيج من الثلاث حاجات دي.
الطريقة القديمة (if/elif): الموظف بيمسك طبق checklist ويبدأ ينزل سطر سطر: "هو ظرف؟ لو أيوة، عليه ختم أحمر؟ لو أيوة، أقل من 100 جرام؟ ...". كل طرد بيكلّفه 14 سؤال متتالي.
الطريقة الجديدة (match): الموظف عنده 6 قوالب جاهزة على الحيط، كل قالب فيه فتحة بشكل الطرد المتوقع. بيرفع الطرد قدّامهم مرة واحدة، القالب اللي ينطبق هو اللي يحدد المسار. أسرع، وأوضح، وأقل احتمالاً للخطأ البشري.
الـ match في Python بيشتغل بنفس الفكرة: بدل ما تكتب 14 شرط متسلسل، بتكتب 6 patterns هيكلية، والمفسّر بيلاقي أول واحد ينطبق.
الشرح العلمي: Structural Pattern Matching من PEP 634
الـ match في Python مش switch من C. switch بيقارن قيمة واحدة بقيم ثابتة. match بيفكّك (deconstruct) القيمة لأجزاء، ويقارن كل جزء بـ pattern. الفكرة مأخوذة من لغات الـ ML family (Haskell, OCaml, Rust, Scala) واسمها رسمياً structural pattern matching.
بحسب PEP 634، الـ pattern في match بيقدر يطابق: قيمة حرفية (literal pattern)، اسم متغير (capture pattern)، نوع class مع unpacking للحقول (class pattern)، sequence بطول معيّن (sequence pattern)، mapping بمفاتيح محددة (mapping pattern)، أو دمج بينهم بـ | (or pattern) و if guard.
الكلمة اللي بتلخّص الفرق: "الشكل". القيمة لازم تنطبق على الـ pattern، مش بس قيمته.
]]>