شرح Python Docstring: دليل شامل لكتابة التوثيق مع أمثلة عملية

1. ما هو docstring في بايثون؟

في بايثون، يُستخدم docstring كـسلسلة نصية خاصة لإضافة وصف أو شرح إلى الدوال، الفئات (classes)، أو الوحدات (modules). يلعب docstring دورًا مهمًا في تحسين قابلية صيانة الكود، ويساعد المطورين الآخرين على فهمه بسهولة. بالإضافة إلى ذلك، يمكن استخدام أدوات توليد التوثيق التلقائية مثل Sphinx لإنشاء وثائق اعتمادًا على docstring.

موقع وصيغة docstring

يتم وضع docstring مباشرة بعد تعريف الدالة أو الفئة أو الوحدة، ويُكتب عادةً باستخدام علامات الاقتباس الثلاثية المزدوجة. الصيغة العامة تكون كالتالي:

def اسم_الدالة(المعاملات):
    """
    هنا نكتب وصفًا مختصرًا للدالة.

    المعاملات:
        اسم_المعامل (النوع): شرح تفصيلي للمعامل
    القيم المعادة:
        النوع: شرح للقيمة المرجعة
    """
    pass

يُستخدم docstring أيضًا في دالة بايثون المدمجة help() وكذلك في بعض المحررات لإظهار المساعدة التوضيحية، مما يجعله عنصرًا أساسيًا في توثيق الكود.

2. كيفية كتابة docstring الأساسية

يُستعمل docstring في بايثون لتوضيح مواصفات الدالة أو الفئة بشكل واضح ومختصر. عادةً يبدأ التوثيق بشرح هدف الدالة، ثم يتبعه توضيح للمعاملات والقيم المعادة والأخطاء المحتملة. الالتزام بدليل الأسلوب الرسمي PEP 257 يساعد على الحفاظ على الاتساق وسهولة الفهم من قبل الآخرين.

البنية الأساسية لـ docstring

يُستخدم docstring أحادي السطر لشرح قصير جدًا، عادةً لتوضيح وظيفة الدالة في كلمة أو جملة:

def add(a, b):
    """إرجاع مجموع رقمين."""
    return a + b

أما docstring متعدد الأسطر فيُستخدم عند الحاجة لتوضيحات أوسع، مثل شرح السلوك والمعاملات والقيم المرجعة:

def add(a, b):
    """
    يقوم بجمع رقمين ويعيد النتيجة.

    المعاملات:
        a (int): الرقم الأول
        b (int): الرقم الثاني

    القيم المعادة:
        int: مجموع الرقمين
    """
    return a + b

3. أنماط docstring (نمط Google، نمط NumPy، نمط reStructuredText)

توجد عدة أنماط لكتابة docstring حسب المشروع أو الأداة المستخدمة. من أشهرها: نمط Google، نمط NumPy، ونمط reStructuredText.

نمط Google

يمتاز نمط Google بالبساطة والوضوح البصري. حيث يتم توثيق المعاملات والقيم المرجعة تحت أقسام مسماة مثل Args وReturns.

def add(a, b):
    """
    إرجاع مجموع رقمين.

    Args:
        a (int): الرقم الأول
        b (int): الرقم الثاني

    Returns:
        int: مجموع الرقمين
    """
    return a + b

نمط NumPy

نمط NumPy يُستخدم على نطاق واسع في مكتبات الحوسبة العلمية وتحليل البيانات. يتم تقسيم الأقسام باستخدام Parameters وReturns مع تفاصيل أوضح.

def add(a, b):
    """
    إرجاع مجموع رقمين.

    Parameters
    ----------
    a : int
        الرقم الأول
    b : int
        الرقم الثاني

    Returns
    -------
    int
        مجموع الرقمين
    """
    return a + b

نمط reStructuredText

يُستخدم هذا النمط بشكل رئيسي مع أداة Sphinx لتوليد التوثيق. حيث يقوم Sphinx بتحويل docstring تلقائيًا إلى مستندات HTML أو PDF.

def add(a, b):
    """
    جمع رقمين.

    :param a: الرقم الأول
    :type a: int
    :param b: الرقم الثاني
    :type b: int
    :return: مجموع الرقمين
    :rtype: int
    """
    return a + b

4. PEP 257 وأفضل الممارسات

يُعتبر PEP 257 دليل الأسلوب الرسمي لكتابة docstring في بايثون. اتباع هذه التوصيات يعزز من قابلية قراءة الكود وسهولة فهمه.

أهم النقاط في PEP 257

  1. docstring أحادي السطر: يُفضل استخدامه مع الدوال البسيطة.
  2. docstring متعدد الأسطر: يُستخدم للتوضيحات التفصيلية مع سطر أول ملخص ثم تفاصيل بعد سطر فارغ.
  3. المسافات الفارغة والمحاذاة: استخدام التهيئة المناسبة يجعل النص أكثر وضوحًا.

أفضل الممارسات

  • وصف واضح وموجز: يجب أن يوضح docstring الغرض من الكود بشكل مباشر.
  • الحفاظ على الاتساق: من المهم أن يكون الأسلوب موحدًا على مستوى المشروع (Google، NumPy، إلخ).

5. الاختبار باستخدام docstring (وحدة doctest)

يوفر بايثون وحدة doctest التي تُمكّن من اختبار أمثلة الكود المكتوبة داخل docstring. هذه الميزة تسمح بالتحقق من أن الأمثلة تعمل كما هو متوقع، مما يزيد من موثوقية الكود.

الاستخدام الأساسي لـ doctest

يقوم doctest بالبحث داخل docstring عن أمثلة الكود وتشغيلها لمقارنة النتائج الفعلية بالنتائج المتوقعة.

def add(a, b):
    """
    إرجاع مجموع رقمين.

    Args:
        a (int): الرقم الأول
        b (int): الرقم الثاني

    Returns:
        int: مجموع الرقمين

    Example:
        >>> add(2, 3)
        5
        >>> add(0, 0)
        0
    """
    return a + b

if __name__ == "__main__":
    import doctest
    doctest.testmod()

في المثال أعلاه، يقوم doctest بتشغيل الأمثلة داخل docstring والتحقق من تطابق النتائج. إذا نجحت الاختبارات فلن يظهر شيء، أما عند الفشل فسيتم عرض رسالة خطأ.

مميزات استخدام doctest

  1. الحفاظ على التناسق: يساعد doctest على ضمان أن الأمثلة داخل docstring تعمل فعلًا، مما يجعل التوثيق والكود متوافقين دائمًا.
  2. أتمتة الاختبارات: يمكن تشغيل الاختبارات تلقائيًا دون الحاجة إلى كتابة اختبارات منفصلة، مما يقلل من الأخطاء ويوفر الوقت.

6. مثال عملي: توثيق الكود باستخدام docstring

استخدام docstring يحسن من قابلية قراءة الكود بشكل كبير، ويُسهل على المطورين الآخرين فهمه. فيما يلي مثال على إضافة docstring إلى فئة (class) ودوالها، ثم استخدام أداة Sphinx لتوليد التوثيق تلقائيًا.

مثال على docstring للفئة

class Calculator:
    """
    فئة آلة حاسبة بسيطة.

    تقوم هذه الفئة بالعمليات الأساسية: الجمع، الطرح، الضرب، القسمة.

    السمات:
        result (int): متغير يخزن النتيجة الحالية.
    """

    def __init__(self):
        """
        مُنشئ الفئة Calculator.
        يتم تعيين النتيجة إلى 0 عند التهيئة.
        """
        self.result = 0

    def add(self, a, b):
        """
        يجمع رقمين ويعيد النتيجة.

        Args:
            a (int): الرقم الأول
            b (int): الرقم الثاني

        Returns:
            int: مجموع الرقمين
        """
        self.result = a + b
        return self.result

إنشاء التوثيق باستخدام Sphinx

يمكن استخدام Sphinx لإنشاء مستندات HTML أو PDF بشكل تلقائي بالاعتماد على docstring.

أولاً، نقوم بتثبيت Sphinx:

pip install sphinx

ثم نستخدم الأمر:

sphinx-quickstart

بعد الإعداد، يمكننا تشغيل:

make html

لإنشاء مستندات HTML تحتوي على docstring المضمنة في ملفات بايثون.

7. الأخطاء الشائعة وكيفية تجنبها

عند كتابة docstring قد يقع المبتدئون في بعض الأخطاء المتكررة. فيما يلي بعض هذه الأخطاء مع طرق معالجتها.

1. الشرح الغامض

ينبغي أن يكون docstring واضحًا ومباشرًا. التوضيحات الغامضة لا تفيد القارئ.

def add(a, b):
    """جمع رقمين."""
    return a + b

المثال أعلاه غير كافٍ لأنه لا يوضح نوع البيانات ولا تفاصيل القيم المعادة. الحل هو إضافة شرح أوضح:

def add(a, b):
    """
    جمع رقمين صحيحين وإرجاع النتيجة.

    Args:
        a (int): الرقم الأول
        b (int): الرقم الثاني

    Returns:
        int: مجموع الرقمين
    """
    return a + b

2. نقص التفاصيل حول المعاملات والقيم المرجعة

إذا لم يتم وصف المعاملات والقيم المرجعة بشكل صحيح داخل docstring، قد يسيء المستخدم فهم وظيفة الدالة.

def divide(a, b):
    """قسمة رقمين."""
    return a / b

هذا المثال لا يوضح ما يحدث عند القسمة على صفر. الحل هو كتابة تفاصيل أكثر:

def divide(a, b):
    """
    قسمة رقمين وإرجاع النتيجة. يثير استثناء ZeroDivisionError إذا كان المقسوم عليه يساوي صفرًا.

    Args:
        a (float): المقسوم
        b (float): المقسوم عليه

    Returns:
        float: نتيجة القسمة

    Raises:
        ZeroDivisionError: عند محاولة القسمة على صفر
    """
    if b == 0:
        raise ZeroDivisionError("لا يمكن القسمة على صفر")
    return a / b

8. الخلاصة: إنشاء توثيق فعال باستخدام docstring

استعرضنا في هذا المقال أهمية docstring في بايثون، وكيفية كتابته بأسلوب صحيح باستخدام أفضل الممارسات واتباع PEP 257. يساعد docstring في تحسين قابلية قراءة الكود وصيانته، ويجعل التعاون بين المطورين أكثر سلاسة.

إنشاء توثيق متناسق وفق PEP 257

اتباع معايير PEP 257 يضمن كتابة docstring متناسق وسهل الفهم، سواء كان في شكل سطر واحد أو عدة أسطر.

التحقق باستخدام doctest

باستخدام doctest يمكن التأكد من أن أمثلة الكود في docstring تعمل بشكل صحيح دائمًا، مما يزيد من موثوقية الكود.

التوليد التلقائي للتوثيق عبر Sphinx

أدوات مثل Sphinx تجعل من السهل تحويل docstring إلى وثائق HTML أو PDF بشكل تلقائي، مما يوفر الوقت ويضمن بقاء التوثيق محدثًا دائمًا مع الكود.

RUNTEQ(ランテック)|超実戦型エンジニア育成スクール