Menu
العربية

تلميحات الأنواع في بايثون: Type Hints بالتفصيل

تعرّف على تلميحات الأنواع في بايثون ومتى تستفيد منها، مع شرح طريقة توثيق المتغيرات ودوال الإدخال والإخراج وأنواع القوائم والقواميس وOptional.

تلميحات الأنواع في بايثون: توصيف لا إلزام

تلميح النوع (type hint) في بايثون هو مجرد ملاحظة تُرفقها باسم ما — غالبًا معامل دالة — تقول فيها "هذا المتغير يُفترض أن يكون int"، أو "هذه الدالة تُرجع قائمة من النصوص"، وهكذا. لكن بايثون لا تفحص هذه التلميحات أثناء التشغيل؛ فلو مرّرت نصًا إلى معامل موسوم بأنه int، لن يحدث أي خطأ. الفائدة الحقيقية تأتي من محرر الأكواد والأدوات الخارجية (مثل mypy، وpyright، وPylance داخل VS Code)، فهي التي تقرأ هذه التلميحات وتنبّهك قبل أن يعمل الكود أصلًا.

إليك أبسط مثال ممكن:

main.py
Output
Click Run to see the output here.

name: str يُوضّح نوع الوسيط، و-> str يُوضّح نوع القيمة المُرجَعة. كلا الاستدعاءين يعملان. الاستدعاء الثاني خاطئ — أي أداة فحص أنواع ساكنة ستُشير إليه — لكنّ بايثون نفسها تُنفّذه دون مشاكل لأنّ 42 يدعم صيغة f"{...}" للاستيفاء.

وهنا النموذج الذهني المهم: تلميحات الأنواع في بايثون ما هي إلا توثيق تستطيع الآلة قراءته. لا تُغيّر شيئًا في وقت التشغيل.

لماذا نستخدمها أصلًا؟

ثلاث فوائد ملموسة، مُرتّبة حسب سرعة ظهور مردودها:

  1. محرّر الأكواد يُصبح أذكى. الإكمال التلقائي يعرض التوابع الصحيحة، وإعادة التسمية تنتشر بدقّة، وتمرير المؤشّر فوق أيّ متغيّر يُظهر لك نوعه.
  2. توقيعات الدوال توثّق نفسها بنفسها. مجرّد النظر إلى def fetch(url: str, timeout: float = 5.0) -> dict: يكفي ليعرف القارئ ما الذي يُمرّره وما الذي سيستقبله — دون الحاجة لقراءة جسم الدالة.
  3. أدوات فحص الأنواع تصطاد الأخطاء قبل تشغيل الكود. تشغيل mypy . على مشروعك يكشف نوع الأخطاء التي كثيرًا ما تُفلت من اختبارات الوحدة — إرجاع None في مكان تتوقّع فيه قيمة، أو استخدام قاموس (dict) في موضع قائمة (list).

إذا كنت تكتب سكربتًا من ملفّ واحد، لك وحدك، وليوم واحد فقط، فلا داعي للتلميحات. أمّا أيّ كود ستعود إليه لاحقًا أو تُشاركه مع غيرك، فالخمس عشرة ثانية التي ستستغرقها في كتابتها ستُوفّر عليك ساعة كاملة لاحقًا.

الأنواع المدمجة الأساسية

الأنواع التالية لا تحتاج إلى أيّ import:

main.py
Output
Click Run to see the output here.

توضيح الأنواع للمتغيرات (name: str = "Rosa") نادراً ما يكون ضرورياً — فبايثون تستنتج النوع من قيمة الطرف الآخر تلقائياً. الأفضل أن تحتفظ بها للوسائط وأنواع القيم المُعادة، وفي الحالات التي يكون فيها النوع المُستنتَج غير واضح.

أما الدوال التي لا تُعيد شيئاً، فنستخدم معها -> None:

main.py
Output
Click Run to see the output here.

القوائم والقواميس والـ Tuples والمجموعات

مع الحاويات (Containers)، تحتاج إلى معلومة إضافية — ما الذي بداخلها. تتيح لك إصدارات بايثون الحديثة استخدام الأقواس المربّعة مباشرة مع الأنواع المدمجة لتحديد نوع العناصر:

main.py
Output
Click Run to see the output here.

لنقرأها بصوت عالٍ:

  • list[float] — قائمة من أعداد float.
  • dict[str, int] — قاموس مفاتيحه نصية وقيمه أعداد صحيحة.
  • tuple[float, float] — تابل يحتوي على عددين عشريين بالضبط.
  • set[str] — مجموعة من السلاسل النصية.

صيغة الأقواس المربعة list[...] و dict[...] مدعومة في Python 3.9 فما فوق. أما في الأكواد الأقدم، فسترى List و Dict و Tuple مستوردةً من typing — المعنى نفسه، لكن بكتابة قديمة.

القيم الاختيارية مع Optional

من الشائع أن تكون القيمة "قد تكون None". وهناك صيغتان متكافئتان للتعبير عن ذلك — كلاهما صحيح، لكن الصيغة الأحدث أوضح في القراءة:

main.py
Output
Click Run to see the output here.

str | None يعني ببساطة "إما نص أو None". صيغة | هذه متاحة ابتداءً من Python 3.10 فما فوق. أما في الأكواد القديمة فسترى Optional[str] المستوردة من وحدة typing، والمعنى واحد في الحالتين.

عندما يرى المستخدم توقيع الدالة -> str | None، يُدرك مباشرةً أن عليه التحقق من None قبل استعمال القيمة المُعادة — وهذه هي الفائدة الحقيقية من تلميحات الأنواع.

أنواع الاتحاد (Union): هذا أو ذاك

حين تحتمل القيمة أكثر من نوع، استخدم |:

main.py
Output
Click Run to see the output here.

يمكنك دمج أكثر من نوعين معًا. فمثلًا int | str | float تعني "أي واحد من هذه الأنواع الثلاثة".

تلميحات الأنواع للمتغيرات داخل الدوال

في أغلب الحالات، تستطيع بايثون استنتاج نوع المتغير المحلي من القيمة التي تُسنَد إليه عند تعريفه، فلا حاجة لكتابة تلميح النوع يدويًا. لن تحتاج إلى إضافة التلميح إلا في الحالات التالية:

main.py
Output
Click Run to see the output here.
  • المُتغيِّر يبدأ فارغًا، فلا يستطيع فاحص الأنواع أن يخمِّن محتواه.
  • القيمة قد تكون من أكثر من نوع وأنت تريد تحديد نوع واحد بشكل صريح.
  • تريد توضيح النيّة للقارئ البشري.

يُعتبر typing.Any بمثابة "باب الهروب"، أي عندما تقول: "لا أرغب في تحديد النوع بدقّة هنا". استخدمه بحذر، لأنّ الإفراط في استعمال Any يُفرِغ بقيّة تلميحات الأنواع من قيمتها.

إضافة تلميحات الأنواع للكلاسات

تُكتب تلميحات الأنواع لخصائص الكلاس وتوقيعات الميثودات بالطريقة نفسها التي نكتبها لأي دالّة عادية:

main.py
Output
Click Run to see the output here.

الكلاسات من نوع dataclass تتطلّب فعليًا استخدام تلميحات الأنواع (type annotations)، لأن الـ decorator الخاص بها @dataclass يقرأ هذه التلميحات ليُولِّد تلقائيًا كلًّا من __init__ و __repr__. وهذه هي الحالة الوحيدة التي تؤثّر فيها تلميحات الأنواع على سلوك البرنامج وقت التشغيل.

الـ Tuples وحالة "الطول غير المحدود"

للتعبير tuple[...] صيغتان يختلط الأمر على المبتدئين بينهما:

main.py
Output
Click Run to see the output here.
  • tuple[float, float] — عنصران من نوع float بالضبط، لا أكثر ولا أقل.
  • tuple[int, ...] — أي عدد من قيم int. الرمز ... (وهو جزء حقيقي من صياغة نظام الأنواع) يعني "وهكذا".

الدوال القابلة للاستدعاء والأسماء المستعارة للأنواع

عندما تستقبل الدالة دالةً أخرى كوسيط أو تُعيدها كقيمة، استخدم Callable:

main.py
Output
Click Run to see the output here.

Callable[[int], int] معناها: "دالة تاخذ int واحد وترجع int".

ولمّا يصير التوصيف متكرّر وطويل، أعطِه اسماً مختصراً:

main.py
Output
Click Run to see the output here.

الاسم المستعار (alias) ما هو إلا عملية إسناد عادية في بايثون. يمكنك استخدام الاسم المختصر في أي مكان كنت ستستخدم فيه الصيغة الطويلة.

تشغيل أداة فحص الأنواع

مفسّر بايثون نفسه يتجاهل تلميحات الأنواع تمامًا. ولكي تقوم فعلًا بفحصها، تحتاج إلى تثبيت أداة متخصصة. mypy هي الأداة الأصلية في هذا المجال، أما pyright (وهي الأداة التي تعتمد عليها Pylance في VS Code) فتتميز بسرعتها الأعلى.

pip install mypy
mypy your_project/

أول تشغيل رح يكشفلك أخطاء في أماكن ما كنت متوقعها. تعامل معها بالتدريج — # type: ignore بيسكّت سطر واحد لما تحتاج تكمّل شغلك.

محررات الكود الحديثة (IDEs) بتشتغل فحص الأنواع بشكل مستمر أثناء الكتابة، فأغلب الملاحظات بتوصلك قبل ما تحفظ الملف.

متى لا تكون تلميحات الأنواع مناسبة

  • سكربتات استكشافية سريعة. إضافة التلميحات بتثقّل كود عمره ساعة واحدة.
  • كود ديناميكي بشكل مكثّف. البرمجة الوصفية (metaprogramming) وأنظمة الإضافات والأنماط المشابهة غالباً بتتجاوز قدرة نظام الأنواع على وصفها. اكتب التلميحات للواجهة الخارجية (API) وخلّي التفاصيل الداخلية مرنة.
  • مكتبات خارجية بدون تلميحات أنواع. لو استوردت مكتبة ما عندها معلومات أنواع، Any رح يتسرّب لكودك. ولا يهمك — مو كودك أنت اللي لازم توثّقه.

أمّا باقي الحالات، فتلميحات الأنواع في بايثون عادة بسيطة بعائد كبير. التكلفة كم ضغطة مفاتيح إضافية على توقيع الدالة، والمقابل أخطاء أقل، وإعادة هيكلة أسهل، وكود بيوثّق نفسه بنفسه.

التالي: الوحدات (Modules) والاستيراد (Imports)

صار بين إيديك كل الأدوات على مستوى الدوال — الوسائط، والـ decorators، وتلميحات الأنواع. في الجزء الجاي رح نشوف كيف بايثون بينظّم الكود عبر عدة ملفات: الوحدات، والحزم (packages)، ونظام الاستيراد.

الأسئلة الشائعة

ما المقصود بـ Type Hints في بايثون؟

هي تعليقات توضيحية تصف الأنواع المتوقعة للمتغيرات ومعاملات الدوال وقيم الإرجاع. بايثون نفسها لا تفرضها وقت التشغيل، فهي موجّهة للأدوات مثل المحررات وأدوات الفحص الساكن (mypy أو pyright)، ولأي شخص يقرأ الكود لاحقًا.

هل تجعل تلميحات الأنواع بايثون أسرع؟

لا. مفسّر بايثون يتجاهل Type Hints وقت التشغيل تمامًا. الفائدة الحقيقية تظهر أثناء التطوير: أخطاء مطبعية أقل، توقيعات دوال أوضح، وإعادة هيكلة أكثر أمانًا.

متى يجب أن أضيف Type Hints إلى كودي؟

أضفها دائمًا إلى توقيعات الدوال العامة (المعاملات ونوع القيمة المُعادة). أما داخل جسم الدالة فاستخدمها باعتدال، فقط عندما لا يكون نوع المتغير واضحًا. في السكربتات الصغيرة تبقى اختيارية، لكن في المكتبات والمشاريع المشتركة فائدتها تظهر بسرعة.

تعلّم البرمجة مع Coddy

ابدأ الآن