كيف تختار أسماء دوال بايثون؟

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

هناك قواعد صارمة لا يُمكنك مخالفتها عند تسمية دوال بايثون وكائنات أخرى. كما توجد قواعد وممارسات فضلى أخرى لا تُسبب أخطاءً عند مخالفتها، ولكنها لا تزال مهمة عند كتابة أكواد بايثون.

اختيار أسماء دوال بايثون المثالية يجعل شيفرتك أسهل قراءةً وصيانتها. كما أن الشيفرة ذات الأسماء المختارة بعناية تكون أقل عرضة للأخطاء.

في هذا الدرس، ستتعلم قواعد تسمية دوال بايثون وأهميتها.

باختصار: استخدم أسماء دوال بايثون الوصفية باستخدام snake_case

في بايثون، تُسمى العلامات التي تستخدمها للإشارة إلى الكائنات مُعرِّفات أو أسماء. يمكنك تعيين اسم لدالة بايثون باستخدام الكلمة المفتاحية def.

عند إنشاء أسماء بايثون، يمكنك استخدام الأحرف الكبيرة والصغيرة، والأرقام من 0 إلى 9، والشرطة السفلية (_). مع ذلك، لا يمكنك استخدام الأرقام كحرف أول. يمكنك استخدام بعض أحرف يونيكود الأخرى في مُعرّفات بايثون، ولكن ليست جميع أحرف يونيكود صالحة. حتى 🐍 ليس صالحًا!

مع ذلك، يُفضّل استخدام الأحرف اللاتينية فقط الموجودة في نظام ASCII. فالأحرف اللاتينية أسهل في الكتابة وأكثر شيوعًا في معظم لوحات المفاتيح. نادرًا ما يُحسّن استخدام أحرف أخرى من سهولة القراءة، وقد يكون مصدرًا للأخطاء.

فيما يلي بعض الأسماء الصحيحة وغير الصحيحة نحويًا لدوال بايثون والكائنات الأخرى:

الاسمالصلاحيةملاحظات
numberصالح
first_nameصالح
first nameغير صالحلا يسمح بالمسافات البيضاء
first_10_numbersصالح
10_numbersغير صالحلا يُسمح بالأرقام في بداية الأسماء
_nameصالح
greeting!غير صالحلا يُسمح باستخدام علامات الترقيم ASCII باستثناء السطر السفلي (_)
caféصالحغير موصى به
你好صالحغير موصى به
hello⁀worldصالحغير مستحسن – أحرف علامات الترقيم الموصلة والعلامات الأخرى هي أحرف صالحة

مع ذلك، لدى بايثون قواعد لتسمية الدوال تتجاوز هذه القواعد. أحد مقترحات تحسين بايثون الأساسية، PEP 8، يُعرّف دليل أسلوب بايثون، الذي يتضمن قواعد التسمية.

وفقًا لإرشادات أسلوب PEP 8، يجب تسمية دوال بايثون بأحرف صغيرة وشرطة سفلية تفصل الكلمات. يُشار إلى هذا الأسلوب عادةً باسم “حالة الثعبان”. على سبيل المثال، يُعد اسم دالة get_text() أفضل من اسم دالة getText() في بايثون.

ينبغي أن تصف أسماء الدوال أيضًا الإجراءات التي تُنفّذها بوضوح ودقة كلما أمكن. على سبيل المثال، بالنسبة لدالة تحسب القيمة الإجمالية لطلب عبر الإنترنت، يُعدّ اسم calculate_total() أفضل من اسم total().

ستستكشف هذه الاتفاقيات وأفضل الممارسات بمزيد من التفصيل في الأقسام التالية من هذا الدرس.

ما هي الحالة التي يجب عليك استخدامها لأسماء دوال بايثون؟

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

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

  • find_winner()
  • save()

يحتوي كلا اسمي الدالتين على أحرف صغيرة، ويحتوي أحدهما على كلمتين إنجليزيتين مفصولتين بعلامة سفلية. يمكنك أيضًا استخدام العلامة السفلية في بداية اسم الدالة أو نهايته. مع ذلك، هناك قواعد تحدد متى يجب استخدامها بهذه الطريقة.

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

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

يمكنك أيضًا استخدام شرطة سفلية واحدة إذا كنت ترغب في إعادة استخدام اسم دالة مدمجة أو كائن آخر. على سبيل المثال، إذا كنت ترغب في تعريف دالة ترغب في استدعائها بـ max، يمكنك تسمية دالتك max_() لتجنب التعارض مع الدالة المدمجة max().

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

تُستخدم أيضًا علامات السطر السفلي المزدوجة للسمات في الفئات. يُؤدي هذا الترميز إلى تشويه الأسماء، مما يُصعّب على المستخدم الوصول إلى السمة ويمنع الفئات الفرعية من الوصول إليها. ستقرأ المزيد عن تشويه الأسماء والسمات ذات العلامات السطرية المزدوجة لاحقًا.

يُعدّ استخدام حالة الثعبان (Snake case) الخيار المُفضّل لتسمية دوال بايثون، كما هو مُوضّح في PEP 8. مع ذلك، لا يُلزِم بايثون باستخدامها، وقد ترى أحيانًا دوالًا تُسمّى بحالة الجمل (camel case). حالة الجمل (camel case)، والتي تُعرف أيضًا بحالة الجمل الصغيرة أو الحالة المختلطة (mixed case)، شائعة في لغات البرمجة الأخرى. ومن أمثلة حالة الجمل دالة findWinner().

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

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

لماذا يجب عليك استخدام أسماء وصفية لأسماء دوال بايثون؟

تُعدّ سهولة القراءة مبدأً أساسياً في البرمجة الحديثة، ولها دورٌ هامٌّ في بايثون. يمكنك جعل شيفرتك أكثر سهولةً في القراءة باختيار أسماء دوال تصف غرضها بوضوح.

خذ بعين الاعتبار الدالة التالية:

def init(n):
    return " ".join(f"{i[0]}." for i in n.split())

يمكنك تحديد الإجراء الذي تنفذه هذه الدالة إذا كنت على دراية بتوابع السلسلة .join() و.split() وبنية تعبير المولد، والتي تشبه بنية التعبير المستخدمة لفهم القائمة.

مع ذلك، اسم الدالة init واسم المعامل n ليسا وصفيين، ولا يوضحان وظيفة الدالة بوضوح. كما أن اسم init قد يُسبب بعض الالتباس نظرًا لتشابهه مع الدالة الخاصة .__init__().

الآن، انظر إلى هذا الإصدار من نفس الدالة:

def get_initials(full_name):
    return " ".join(f"{name[0]}." for name in full_name.split())

الغرض من هذه الدالة أوضح في هذا الإصدار، حيث يصف اسم الدالة get_initials() عملها. يمكنك التأكد من أن الدالة تعمل كما تتوقع:

>>> def get_initials(full_name):
...     return " ".join(f"{name[0]}." for name in full_name.split())

>>> get_initials("James Clerk Maxwell")
J. C. M.
>>> get_initials("Richard Feynman")
R. F.

تساعدك أسماء الدوال والمعلمات على فهم الكود في نص الدالة. تؤكد استدعاءات الدالة أن دالة get_initials() تُرجع الأحرف الأولى من أي اسم كامل.

يُسهّل اسم المعلمة full_name أيضًا القراءة. يُقرأ السطر الذي يُعرّف الدالة الآن كـ get initials (from) full name. كلمة from مفقودة، ولكن يُمكن فهمها بسهولة من قِبل قارئ الكود. يُمكنك أيضًا استخدام get_initials_from() إذا كنت ترغب في توضيح أكثر.

تُمكّنك هذه التسمية من استخدام الدوال كوحدات بناء عالية المستوى، إذ يُشير اسمها إلى وظيفتها، ولا داعي للقلق بشأن كيفية تطبيقها على مستوى أدنى. يمكن استخدام الدالة كصندوق أسود بعد تعريفها واختبارها، ويُعد الاسم الوصفي جزءًا مهمًا من وثائق الدالة.

يجب عليك أيضًا تجنب الأسماء الطويلة غير الضرورية. فهي تجعل الكود أكثر إطنابًا وتؤدي إلى أسطر أطول، مما قد يتطلب التمرير أو التقسيم إلى أسطر متعددة. لذلك، تُعدّ دالة get_initials() حلاً وسطًا معقولًا بين سهولة القراءة وطول الاسم.

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

إليك مثال آخر. تكتب دالة لإيجاد عدد حروف العلة في نص. يمكنك تسمية دالتك find_number_of_vowels(). هذا الاسم واضح، وقد يختاره العديد من المبرمجين.

مع ذلك، قد يفضل آخرون صيغة أقصر وأسهل قراءة: find_num_vowels(). اختصار number إلى num اختصار مفهوم، ويمكن أيضًا حذف حرف الجر of بأمان. قد يختار بعض المبرمجين استخدام find_n_vowels(). تُركز الصيغة الأقصر بشكل أكبر على الجزء المهم من الاسم، وهو في هذه الحالة حرف العلة.

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

ومع ذلك، لم تعد هناك حاجة إلى أسماء قصيرة نظرًا لأن القيود التي كانت مفروضة في السنوات الأولى لم تعد ذات صلة اليوم، كما أن المحررين الحديثين لديهم أدوات مفيدة مثل الإكمال التلقائي للأسماء.

بالإضافة إلى ذلك، بما أن أجهزة الكمبيوتر اليوم قادرة على التعامل مع متطلبات أعلى، أصبحت البرامج أطول وأكثر تعقيدًا مما كانت عليه في بدايات الحوسبة. ونتيجةً لذلك، ازدادت أهمية سهولة قراءة الكود على مر السنين، ويُعدّ اختيار أسماء الدوال أداةً يمكن للمبرمجين استخدامها لتسهيل قراءة الكود وصيانته. كما أن سهولة قراءة الكود تُقلل من احتمالية وجود أخطاء.

ما هي اتفاقيات التسمية للتوابع؟

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

لقد تعلمت سابقًا في هذا الدرس أن هناك قواعد عامة لاستخدام الشرطات السفلية في بداية أو نهاية اسم الدالة. الاستخدام الأكثر شيوعًا للشرطات السفلية في طرفي اسم الدالة يرتبط بدوائر خاصة. هذه الدوال هي دوال تستدعيها بايثون لإجراء عمليات محددة على كائن.

تتضمن أسماء التوابع الخاصة شرطتين سفليتين رئيسيتين وشرطتين سفليتين لاحقتين، كما هو الحال مع .__init__(). أدى وجود الشرطتين السفليتين المزدوجتين إلى تسمية هذه التوابع بشكل غير رسمي بـ “توابع dunder”.

لإظهار عدد من التوابع وأسمائها، يمكنك إنشاء فئة BankAccount ونص برمجي يسمى bank_account.py:

class BankAccount:
    def __init__(self, account_number, balance):
        self.account_number = account_number
        self.balance = balance

    def __repr__(self):
        return (
          f"{type(self).__name__}({self.account_number}, {self.balance})"
        )

تتضمن الفئة تابعين خاصتين، ولكل منهما شرطتان سفليتان رئيسيتان وشرطتان سفليتان لاحقتان كجزء من أسمائهما:

  • يتم استدعاء .__init__() عند إنشاء مثيل لفئة. يقوم بتهيئة الكائن.
  • .__repr__() يحدد التمثيل النصي الرسمي لكائن، والذي يتضمن معلومات حول اسم الفصل وحججه.

تذكّر أنه لا يمكنك اختيار أسماء الدوال الخاصة لأنها جزء لا يتجزأ من لغة بايثون. كما يجب عدم استخدام أسماء ذات شرطتين سفليتين في البداية وشرطتين سفليتين في نهايتها لأي دوال أخرى غير دوال بايثون الخاصة.

يمكنك إضافة المزيد من التوابع إلى هذه الفئة:

class BankAccount:
    # ...

    def get_balance(self):
        return self.balance

    def withdraw(self, amount):
        ...

التابع الأولى الذي يمكنك إضافته هو .get_balance()، والتي تتبع اتفاقيات تسمية الدالة التي تعلمتها سابقًا:

  • اسم التابع هو في حالة الثعبان.
  • يصف الاسم التابع بوضوح. الكلمة الأولى في الاسم هي الفعل get لتوضيح الإجراء الذي يؤديه التابع.

كما هو الحال مع أسماء الدوال، يجب أن تكون أسماء التوابع عبارة عن فعل أو تبدأ بفعل لتسليط الضوء على الإجراء الذي تقوم به عندما يكون ذلك مناسبًا.

التابع التالي الذي تُعرّفها هي .withdraw()، والتي تتبع أيضًا نفس القواعد. يستدعى هذه التابع بتمرير مبلغ إليها، مثل .withdraw(50). وبالتالي، يُوضّح الاستدعاء رغبتك في سحب 50 دولارًا أمريكيًا.

هذه الطريقة لا تحتوي على أي شيفرة برمجية حتى الآن. يجب أن تُنفِّذ الإجراءات التالية:

  • تأكد من أن رصيد الحساب أكبر من أو يساوي المبلغ المراد سحبه
  • خصم المبلغ من رصيد الحساب إذا كان هناك رصيد كاف
  • إرجاع صحيح إذا كان السحب ناجحًا أو خطأ إذا لم يتم سحب أي أموال

يمكنك تعريف تابعين، يسمى verify_funds() وdeduct_funds()، لاستخدامهما في هذه الطريقة وأجزاء أخرى من تعريف الفئة. مع ذلك، ستختار أسماءً مُعدّلة قليلاً لهاتين التابعين. أولًا، فكّر في طريقة التحقق من وجود رصيد كافٍ في الحساب.

تريد استخدام هذا التابع ضمن تعريف الفئة، ولكن لا تريد جعلها جزءًا من واجهة هذه الفئة. لا يحتاج مستخدم هذه الفئة إلى استدعاء هذه التابع. لتوضيح كيفية استخدام هذه التابع، يمكنك إضافة شرطة سفلية واحدة إلى اسم التابع:

class BankAccount:
    # ...

    def _verify_funds(self, amount):
        return self.balance >= amount

    # ...

لا يمنع هذا الترميز أي مستخدم للفئة من استدعاء هذه الدالة مباشرةً. يمكنك التأكد من ذلك في جلسة REPL:

>>> from bank_account import BankAccount
>>> debit_account = BankAccount(1111, 50)
>>> debit_account._verify_funds(25)
True

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

تُظهر الاقتراحات سمتي البيانات، .account_number و.balance، والتابعين .withdraw() و.get_balance(). أما بقية الاقتراحات فهي توابع خاصة ببايثون.

التابع الذي عرّفته بعلامة سفلية بادئة، ._verify_funds()، غير معروض ولن يكمّل تلقائيًا بإعدادات PyCharm الافتراضية. مع ذلك، لا يزال بإمكانك كتابتها كاملةً واستدعاء الدالة، كما فعلت في جلسة REPL. تُشير بعض اللغات إلى هذه السمات باسم “خاصة”. مع ذلك، يُفضّل في بايثون استخدام مصطلح “غير عام” للسمات التي تبدأ بعلامة سفلية.

تحتاج أيضًا إلى تابع لخصم الأموال من الحساب وكتابة الكود في .withdraw() في هذه المرحلة:

class BankAccount:
    def __init__(self, account_number, balance):
        self.account_number = account_number
        self.balance = balance

    def __repr__(self):
        return (
          f"{type(self).__name__}({self.account_number}, {self.balance})"
        )

    def _verify_funds(self, amount):
        return self.balance >= amount

    def _deduct_funds(self, amount):
        self.balance -= amount

    def get_balance(self):
        return self.balance

    def withdraw(self, amount):
        if self._verify_funds(amount):
            self._deduct_funds(amount)
            return True
        return False

أضف تابعين إضافيين إلى هذه الفئة:

class BankAccount:
    def __init__(self, account_number, balance):
        self.account_number = account_number
        self.balance = balance

    def __repr__(self):
        return (
          f"{type(self).__name__}({self.account_number}, {self.balance})"
        )

    def _verify_funds(self, amount):
        return self.balance >= amount

    def _deduct_funds(self, amount):
        self.balance -= amount

    def _add_funds(self, amount):
        self.balance += amount

    def get_balance(self):
        return self.balance

    def withdraw(self, amount):
        if self._verify_funds(amount):
            self._deduct_funds(amount)
            return True
        return False

    def deposit(self, amount):
        self._add_funds(amount)
        return True

التابع .deposit() جزء من واجهة الفئة، إذ لا يحتوي على أي شرطات سفلية في اسمه. يمكنك استخدامه عند إنشاء مثيل للفئة. مع ذلك، يحتوي التابع ._add_funds() على شرطات سفلية لجعلها غير عامة.

يمكنك اختبار هذه الفئة في جلسة REPL جديدة:

>>> from bank_account import BankAccount
>>> debit_account = BankAccount(1111, 50)
>>> debit_account.get_balance()
50

>>> debit_account.withdraw(32.50)
True
>>> debit_account.get_balance()
17.5

>>> debit_account.withdraw(22.75)
False
>>> debit_account.get_balance()
17.5

>>> debit_account.deposit(10)
True
>>> debit_account.get_balance()
27.5

عند استخدام الفئة لإنشاء مثيل، يمكنك تنفيذ جميع الإجراءات باستخدام دوال المثيل التي لا تحتوي على شرطات سفلية بادئة. ينجح استدعاء دالة .withdraw() الأولى، ويُحدّث رصيد الحساب المصرفي. أما استدعاء دالة .withdraw() الثانية، فيفشل لأن المبلغ المطلوب أكبر من رصيد الحساب. تُرجع الدالة القيمة False. يمكنك استدعاء دالة .deposit() لزيادة رصيد الحساب.

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

لا تُلزم بايثون بهذه الإرشادات في التسمية. مع ذلك، يتبع معظم المبرمجين هذه القواعد لضمان الاتساق وتحسين قابلية القراءة. يمكنك مراعاة هذه القواعد عند اختيار اسم لدالة جديدة في المرة القادمة.


اكتشاف المزيد من بايثون العربي

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

Scroll to Top

اكتشاف المزيد من بايثون العربي

اشترك الآن للاستمرار في القراءة والحصول على حق الوصول إلى الأرشيف الكامل.

Continue reading