المستوى: مبتدئ
اكتب Type Hints في Python ومش هتشوف TypeError مرة تانية في الإنتاج. سطر واحد فوق كل دالة بيخلّي الـ IDE والـ mypy يقولّك على الـ bug قبل ما تضغط Run.
Type Hints في Python: المفهوم اللي بيوفّر 80% من Debugging Time
المشكلة باختصار
Python لغة dynamic typing. المتغير الواحد ممكن يكون int النهارده و str بكره و list بعده، والـ interpreter مش هيعترض. ده مرن لكنه بيخلّي حوالي 30% من bugs الإنتاج سببها قيمة بنوع غلط مرّت من دالة لدالة لحد ما حصل crash جوّه deep stack مفيش حد فاهمه.
Type Hints بتقفل الباب ده static-time قبل ما الكود يتشغّل. الـ interpreter بيتجاهلها runtime، لكن أدوات زي mypy و pyright بتمسك الخطأ وانت بتكتب.
المفهوم بمثال بسيط
تخيّل موظف استقبال في فندق. لو الزبون قاله "أنا حجزت غرفة"، الموظف بيسأله عن اسم الحجز ورقم البطاقة. لو الزبون مدّ له ورقة كتب عليها "كرسي" بدل اسم، الموظف هيرفض في ثانية. الموظف عنده قائمة بالأنواع المقبولة لكل مدخل.
Python بدون Type Hints هو موظف الاستقبال اللي بيستلم أي حاجة بدون مراجعة، وبيكتشف إن الورقة فيها كلمة "كرسي" بعد ما يكون عمل 5 خطوات تانية اعتماداً عليها. Type Hints بتديله القائمة من الأول.
التعريف العلمي
طبقاً لـ PEP 484 (Sept 2014، اللي اعتُمد في Python 3.5)، Type Hints هي annotations بتتكتب على الـ function parameters والـ return type لتوضيح النوع المتوقع. الـ Python interpreter بيتجاهلها كلياً وقت التشغيل (مفيش overhead)، لكن type checkers زي mypy و pyright و Pyre بتقرأها وبتعمل static analysis قبل التشغيل لاكتشاف عدم التوافق.
الكود قبل وبعد
قبل Type Hints
def calculate_discount(price, discount_percent):
return price - (price * discount_percent / 100)
# طلب جاي من JSON API، السعر اتحوّل string من غير ما تحس
result = calculate_discount("499.99", 15)
print(result)
# TypeError: unsupported operand type(s) for -: 'str' and 'float'
# هتكتشف الخطأ ده في الإنتاج مع 200 user قاعدين يحاولوا يدفعوا
بعد Type Hints
def calculate_discount(price: float, discount_percent: float) -> float:
return price - (price * discount_percent / 100)
result = calculate_discount("499.99", 15)
# mypy بيطلع الخطأ ده فوراً وانت لسه بتكتب:
# Argument 1 to "calculate_discount" has incompatible type "str"; expected "float"
الفرق الجوهري: في الحالة الأولى الـ bug بيظهر في الإنتاج. في الحالة التانية بيظهر في الـ IDE قبل ما تـ commit أصلاً.
3 خطوات لتفعيل Type Checking في مشروع موجود
- ثبّت mypy:
pip install mypy - ابدأ بأهم دالة في الكود (الأكثر استدعاءً) وضيف types للـ parameters والـ return فقط. مش لازم تغطي كل الكود في يوم.
- شغّل التحقق:
mypy your_module.py --strictهيطلع لك كل المشاكل المحتملة. صلّح اللي يهمّك واتجاهل الباقي بـ# type: ignoreمؤقتاً.
الأنواع الأساسية اللي هتستخدمها يومياً
from typing import Optional
# قيمة ممكن ترجع None
def get_user(user_id: int) -> Optional[dict]:
if user_id > 0:
return {"name": "أحمد", "age": 30}
return None
# قائمة من نوع محدد
def sum_prices(prices: list[float]) -> float:
return sum(prices)
# Dictionary بمفتاح وقيمة من نوع محدد
def get_config(env: str) -> dict[str, str]:
return {"db": "postgres", "cache": "redis"}
# دالة ممكن تستقبل أكتر من نوع
def stringify(value: int | float | str) -> str:
return str(value)
أرقام من الإنتاج
Dropbox نشروا تجربتهم سنة 2019: ضافوا Type Hints على codebase حجمه 4 مليون سطر Python على مدار 3 سنين. النتيجة المُعلنة: bugs الإنتاج المرتبطة بأنواع البيانات نزلت بنسبة ~90%، ووقت onboarding المهندسين الجدد قلّ من 6 أسابيع لـ 3 أسابيع لأن أي مهندس بقى يقدر يقرا أي دالة ويفهم input/output منها فوراً.
Trade-offs لازم تعرفها
- المكسب: 80%+ من type bugs بتتمسك قبل التشغيل. الـ autocomplete في VS Code و PyCharm بيبقى دقيق لأن الـ IDE عارف النوع المتوقع.
- الخسارة: 5–10% زيادة في كمية الكود (سطر annotations لكل دالة). وقت تعلّم mypy syntax، يومين تقريباً للمبتدئ لحد ما يفهم Optional و Union.
- الافتراض: الكلام ده على Python 3.10+. الإصدارات الأقدم محتاجة
from typing import List, Dictبدل النسخة الـ built-inlist[float]. - تكلفة CI: mypy على codebase 50 ألف سطر بياخد ~12 ثانية على لاب توب 2024. غير ملحوظ في pipeline.
متى لا تستخدم Type Hints
سكربت سريع 30 سطر مش هيتشغل تاني، أو Jupyter notebook استكشافي للبيانات بتجرّب فيه أفكار. هنا Type Hints بتبطّأ السرعة بدون فايدة حقيقية. لكن أي خدمة production أو library عام أو حتى script هيتنفّذ في cron job، Type Hints أصبحت معيار صناعي مش رفاهية.
كمان لو الكود بتاعك بيعتمد بشكل كبير على metaprogramming أو dynamic attribute creation (مثل ORM models قديمة)، mypy هيقعد يصرخ على حاجات صحيحة، والاستثمار مش هيستاهل.
الخطوة التالية
افتح أكبر دالة في مشروعك دلوقتي، وضيف type hints للـ parameters فقط (سيب الـ return لحد ما تتعوّد). شغّل mypy your_file.py. لو طلعت لك أخطاء، انت كده اكتشفت bugs كانت مدفونة في الكود من شهور وما حدش لاحظها.
المصادر
- PEP 484 — Type Hints (Python.org): peps.python.org/pep-0484
- PEP 604 — Allow writing union types as X | Y: peps.python.org/pep-0604
- mypy Documentation: mypy.readthedocs.io/en/stable
- Python Typing Module: docs.python.org/3/library/typing.html
- Dropbox Engineering — "Our journey to type checking 4 million lines of Python": dropbox.tech/application/our-journey-to-type-checking-4-million-lines-of-python
- Microsoft Pyright: github.com/microsoft/pyright