تعريف الدوال في بايثون

من موسوعة حسوب

تُعرَّف الدوال باستخدام الكلمة المفتاحية def يتبعها اسم الدالة ثم قائمة بالمعاملات محاطة بالأقواس. أما الكتلة الرئيسية للدالة فتبدأ في السطر التالي لسطر التعريف، ويجب أن تزاح بمقدار إزاحة واحدة.

مثال

>>> def fib(n): # دالة لإنشاء متسلسلة فابيوناتشي
...     """Print a Fibonacci series up to n."""
...     a, b = 0, 1
...     while a < n:
...         print(a, end=' ')
...         a, b = b, a+b
...         print()
...
>>> # استدعاء الدالة
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

يمكن أن تكون العبارة الأولى في كتلة الدالة سلسلة نصّية، وتمثّل سلسلة التوثيق النصية الخاصة بتلك الدالة ويطلق عليها أيضًا تسمية docstring. (يمكن الاطلاع على المزيد من المعلومات حول سلاسل التوثيق النصية في قسم سلاسل التوثيق النصية).

هناك أدوات تستخدم سلاسل التوثيق النصية لإنتاج توثيق عبر شبكة الإنترنت، أو تسمح للمستخدم بتصفح الشيفرة بصورة تفاعلية؛ لذا ينصح باستخدام سلاسل التوثيق النصية في الشيفرة التي تكتبها.

يؤدي تنفيذ الدالة إلى إنشاء رمز جدول جديد يستخدم للمتغيرات المحلية التابعة للدالة. وبصورة أدق، في كلّ مرة تجري فيها عملية إسناد لمتغير معيّن تخزّن قيمة المتغير في جدول الرموز المحلي (local symbol table)، أما عند الإشارة إلى المتغيرات فإنّ اللغة تبحث بداية في جدول الرموز المحلي، ثم في جدول الرموز المحلي الخاص بالدالة التي يرتبط بها المتغير، ثم في جدول الرموز العام، وأخيرًا في في جدول الأسماء المضمّنة في اللغة.

ولهذا السبب، لا يمكن إسناد القيم إلى المتغيّر العامّة وبصورة مباشرة داخل الدالة (إلا إذا سمّيت ضمن عبارة عامة)، ولكن يمكن الإشارة إلى هذه المتغيرات.

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

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

>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89

إن كنت تمتلك خلفية برمجية في اللغات الأخرى فإنّك قد تعترض على أنّه لا يمكن اعتبار fib دالة وإنّما هي مجرّد إجراء (procedure) وذلك لأنّها لا تعيد قيمة. في الواقع، حتى الدوال التي لا تتضمّن عبارة return مهما كانت بسيطة فإنّها تعيد قيمة. هذه القيمة هي None (وهو اسم محجوز في اللغة). لا يعرض المفسّر القيمة None في حال كانت القيمة الوحيدة المعادة، ولرؤية هذه القيمة يمكن استخدام الدالة print():

>>> fib(0)
>>> print(fib(0))
None

يمكن كتابة دالة تعيد قائمة بأعداد متسلسلة فابيوناتشي بدلًا من طباعتها فقط:

>>> def fib2(n): # تعيد متسلسلة فابيوناتشي
...     """Return a list containing the Fibonacci series up to n."""
...     result = []
...     a, b = 0, 1
...     while a < n:
...         result.append(a) # انظر أدناه
...         a, b = b, a+b
...         return result
...
>>> f100 = fib2(100) # استدعاء الدالة
>>> f100 # كتابة النتائج
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

تعيد العبارة return القيمة المحدّدة بعدها، وفي حال عدم استخدام أي عبارة بعد return فإنّها ستعيد None وكذلك الأمر في حال عدم استخدام return في نهاية الدالة.

تستدعي العبارة result.append(a)‎ تابعًا لكائن القائمة result، والتابع هو دالة تنتمي إلى كائن ويكون بالصيغة namedobj.methodname، إذ يشير obj إلى كائن معين (وقد يكون تعبيرًا أيضًا) أما methodname فتمثّل اسم التابع المعرّف ضمن نوع الكائن. تمتلك الأنواع المختلفة توابع مختلفة، وقد تمتلك التوابع الخاصّة بأنواع مختلفة أسماء متشابهة دون حدوث تضارب فيما بينها. (يمكنك تعريف أنواع الكائنات والتوابع الخاصّة بك وذلك باستخدام الأصناف، راجع الأصناف).

في المثال السابق، التابع append() مُعرَّف في كائنات القوائم list، ومهمّته إضافة عنصر جديد إلى نهاية القائمة، وهو مكافئ للعبارة result = result + [a]‎ ولكنّه أكثر كفاءة.

حواشي الدوال

حواشي الدوال Function Annotations هي معلومات اختيارية حول الأنواع المستخدمة في الدوال المعرّفة من قبل المستخدم.

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

>>> def f(ham: str, eggs: str = 'eggs') -> str:
... print("Annotations:", f.__annotations__)
... print("Arguments:", ham, eggs)
... return ham + ' and ' + eggs
...
>>> f('spam')
Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}
Arguments: spam eggs
'spam and eggs'

مصادر