تلميحات النوع في بايثون: كتابة كود أكثر أمانًا ووضوحًا
ربما صادفت دالة بايثون تُرجع أنواعًا مختلفة اعتمادًا على المدخلات، أو متغيرًا يغيّر نوعه في منتصف الطريق. تؤدي هذه الغموض إلى أخطاء وقت التشغيل كان يمكن اكتشافها مبكرًا. تحل تلميحات النوع في بايثون هذه المشكلة من خلال السماح لك بتعليق الأنواع المتوقعة، مما يجعل الكود موثقًا ذاتيًا ويمكّن أدوات التحليل الثابت من اكتشاف الأخطاء قبل التنفيذ.
في هذا المقال، سنستكشف كيفية استخدام تلميحات النوع في بايثون بفعالية، من التعليقات الأساسية إلى الأنماط المتقدمة، وكيف تساهم في كود أكثر أمانًا ووضوحًا.
ما هي تلميحات النوع في بايثون؟
تلميحات النوع (وتسمى أيضًا تعليقات النوع) هي صيغة تم تقديمها في بايثون 3.5 (PEP 484) تتيح لك تحديد الأنواع المتوقعة للمتغيرات ومعاملات الدوال وقيم الإرجاع. لا يتم فرضها في وقت التشغيل ولكن تستخدمها أدوات فحص النوع الثابت مثل mypy وpyright وبيئات التطوير المتكاملة لاكتشاف الأخطاء المتعلقة بالأنواع.
على سبيل المثال:
def greet(name: str) -> str:
return f"Hello, {name}"
هنا، name: str يشير إلى أن name يجب أن يكون سلسلة نصية، و-> str يشير إلى أن الدالة تُرجع سلسلة نصية.
لماذا تستخدم تلميحات النوع؟
- اكتشاف الأخطاء مبكرًا: يمكن لأدوات فحص النوع الثابت اكتشاف عدم تطابق الأنواع قبل تشغيل الكود.
- تحسين القراءة: تعمل تلميحات النوع كتوثيق مضمّن، مما يسهل على الآخرين (وعلى نفسك في المستقبل) فهم الكود.
- دعم أفضل لبيئة التطوير: يصبح الإكمال التلقائي وإعادة الهيكلة والتنقل أكثر دقة.
- تعزيز قابلية الصيانة: عند إعادة الهيكلة، تساعد تلميحات النوع في ضمان عدم كسر العقود.
- تسهيل التعاون: يمكن للفرق توصيل الواجهات المتوقعة بوضوح.
تعليقات النوع الأساسية
يمكنك تعليق المتغيرات ومعاملات الدوال وأنواع الإرجاع.
المتغيرات
age: int = 30
name: str = "Alice"
الدوال
def add(a: int, b: int) -> int:
return a + b
المجموعات
للقوائم والقواميس وغيرها، استخدم وحدة typing (أو الأنواع العامة المدمجة في بايثون 3.9+):
from typing import List, Dict
def process(items: List[str]) -> Dict[str, int]:
return {item: len(item) for item in items}
في بايثون 3.9+، يمكنك استخدام list[str] وdict[str, int] مباشرة.
تلميحات النوع المتقدمة
مع نمو الكود، ستواجه سيناريوهات أكثر تعقيدًا. إليك بعض الميزات المتقدمة.
Optional و Union
Optional[T] هو اختصار لـ Union[T, None]، مما يشير إلى قيمة يمكن أن تكون من النوع T أو None.
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
# returns username or None if not found
...
في بايثون 3.10+، يمكنك استخدام عامل |: str | None.
Callable
للدوال كوسائط:
from typing import Callable
def apply_func(func: Callable[[int], int], value: int) -> int:
return func(value)
Generics
أنشئ مكونات قابلة لإعادة الاستخدام باستخدام متغيرات النوع:
from typing import TypeVar, List
T = TypeVar('T')
def first(items: List[T]) -> T:
return items[0]
TypedDict
للقواميس التي تحتوي على مجموعة ثابتة من المفاتيح وأنواع القيم:
from typing import TypedDict
class User(TypedDict):
name: str
age: int
def greet(user: User) -> str:
return f"Hello, {user['name']}"
استخدام أدوات فحص النوع الثابت
تلميحات النوع مفيدة فقط إذا قمت بفحصها. تشمل الأدوات الشائعة mypy وpyright وpyre. دعنا نرى كيفية استخدام mypy.
- تثبيت mypy:
pip install mypy - تشغيله على الكود:
mypy your_script.py - إصلاح الأخطاء المبلغ عنها.
على سبيل المثال، بالنظر إلى:
def add(a: int, b: int) -> int:
return a + b
add("1", "2")
سيبلغ mypy: error: Argument 1 to "add" has incompatible type "str"; expected "int".
يمكنك تكوين mypy عبر ملف mypy.ini أو pyproject.toml لفرض فحوصات أكثر صرامة.
أفضل الممارسات لتلميحات النوع
- كن متسقًا: علّق جميع الدوال والطرق العامة.
- استخدم
Anyباعتدال: فهو يعطل فحص النوع لتلك القيمة. - فضّل الأنواع الملموسة على
Anyأوobject. - استخدم
Optionalللقيم التي يمكن أن تكون None. - استفد من
Protocolللأنواع الفرعية الهيكلية (duck typing مع أمان النوع). - حافظ على تحديث تلميحات النوع عند إعادة الهيكلة.
- شغّل فاحص النوع في CI لاكتشاف المشكلات مبكرًا.
المزالق الشائعة وكيفية تجنبها
- تجاهل أخطاء النوع: لا تكتم mypy فقط؛ افهم المشكلة وأصلحها.
- الإفراط في استخدام
Any: يهدم الغرض من تلميحات النوع. - نسيان تعليق أنواع الإرجاع: خاصة للدوال التي تُرجع None.
- استخدام وسائط افتراضية قابلة للتغيير مع تلميحات النوع: هذه مشكلة منفصلة في بايثون، لكن تلميحات النوع لن تكتشفها.
- عدم تحديث التلميحات بعد التغييرات: يؤدي إلى ثقة زائفة.
تلميحات النوع عمليًا: مثال صغير
لنأخذ دالة تعالج قائمة أرقام وتُرجع المتوسط. بدون تلميحات النوع، ليس واضحًا ما الأنواع المتوقعة.
def average(numbers):
return sum(numbers) / len(numbers)
مع تلميحات النوع:
from typing import List
def average(numbers: List[float]) -> float:
return sum(numbers) / len(numbers)
الآن، إذا مرر شخص ما قائمة سلاسل نصية، سيشير mypy إلى ذلك.
دمج تلميحات النوع في سير عملك
للحصول على أقصى استفادة من تلميحات النوع، ادمجها في عملية التطوير:
- أضف تلميحات النوع تدريجيًا إلى قواعد الكود الموجودة.
- قم بتكوين IDE لعرض أخطاء النوع.
- أضف خطوة فحص النوع إلى خط أنابيب CI.
- استخدم خطافات pre-commit لتشغيل mypy قبل الالتزامات.
على سبيل المثال، خطوة سير عمل GitHub Actions بسيطة:
- name: Type check
run: mypy .
الأسئلة الشائعة
هل تؤثر تلميحات النوع على أداء وقت التشغيل؟
لا، يتم تجاهل تلميحات النوع في وقت التشغيل. يتم تخزينها في __annotations__ ولكنها لا تؤثر على سرعة التنفيذ.
هل يمكنني استخدام تلميحات النوع في إصدارات بايثون الأقدم؟
تم تقديم تلميحات النوع في بايثون 3.5. للإصدارات الأقدم، يمكنك استخدام تعليقات قائمة على التعليقات (مثل # type: int)، لكن يوصى بالترقية إلى إصدار بايثون مدعوم.
ما الفرق بين List وlist في تلميحات النوع؟
List من typing يُستخدم في بايثون 3.5-3.8. في بايثون 3.9+، يمكنك استخدام list المدمج مباشرة. كلاهما متكافئ لفحص النوع.
هل أنت مستعد لتحسين جودة الكود؟ ابدأ بإضافة تلميحات النوع إلى دالة واحدة اليوم وشغّل mypy لترى الفوائد. لمزيد من أدوات المطورين، تحقق من منسق JSON لتجميل والتحقق من بيانات JSON الخاصة بك دون عناء.