الدوال والوحدات في بايثون – سلسلة بايثونات لتعلم لغة البايثون

6 6٬269

أهلًا بكم في المقال الخامس من سلسلة بايثونات لتعلم البايثون. نتكلم في هذا المقال حول موضوع الدوال والوحدات في بايثون ومن خلاله سنعرف كيف نُعرف دالة function في بايثون وكيف نتعامل مع الوحدات والمكتبات المُضمنة في بيئة بايثون.

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

  1. لغة بايثون للمبتدئين – سلسلة بايثونات لتعلم البايثون والانطلاق في عالم البرمجة.
  2. النصوص في بايثون.
  3. المتغيرات والتراكيب في بايثون.
  4. جُمل التحكم في بايثون.
  5. الدوال والوحدات بايثون.
  6. مُعالجة الأخطاء في بايثون.
  7. البرمجة الكائنية في بايثون.
الدوال والوحدات في بايثون
الدوال والوحدات في بايثون

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

الدالة عبارة عن كتلة من شيفرة برمجية لها إسم أو عنوان نضعه لهذه الكتلة (اسم الدالة) ويتم استدعاء هذه الكتلة عند الحاجة إليها لتنفيذ الشيفرة البرمجية التي بداخلها. يُمكن تعريف الدالة بحيث تستقبل معاملات parameters وتكون هذه المعاملات عبارة عن مُدخلات يتم استخدامها داخل الشيفرة البرمجية الخاصة بالدالة.

لتعريف دالة في البايثون نستخدم الكلمة المحجوزة def والتي تُحدد بدء تعريف الدالة:
def function_name(parameter_1, paramter_2):
print(parameter_1, parameter_2)

لاستدعاء الدالة، نكتب الإسم الخاص بها ثم نكتب قوس ونُغلقه اذا لم يكن هناك مُعطيات arguments سنمررها لها، وإلا نكتب المعطيات ثم نُغلق القوس.

في المثال التالي نُعرف متغير باسم x ونُعطيه قيمة 10 ونُعرف مُتغير آخر باسم y ونُعطيه قيمة 5، ثُم نُعرف دالة باسم multiply تقوم بطباعة نتيجة ضرب قيمة المتغيرين بعد تمريرهما لها. لتشغيل الشيفرة البرمجية اضغط على زر run:

x = 10 
y = 5

def multiply(a,b):
result = a * y
print("Result is: " , result)

multiply(x,y)

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

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

x = 10 
y = 5

def multiply(a,b):
result = a * y
return result

print(multiply(x,y))

طُرق استدعاء الدوال في البايثون

نُلاحظ في المثال السابق أننا استدعينا الدالة من خلال تمرير نفس العدد من المعاملات التي عرفنا فيها الدالة. لو مررنا معاملين بدل ثلاثة للدالة sum_triple سيظهر لنا خطأ TypeError: missing 1 required positional argument وسُيسمي لك اسم المعامل الذي لم يأخذ قيمة.

السبب هنا هو أن استدعاء الدالة يتم بشكل تلقائي وفق طريقة “أماكن المعاملات” والتي فيها يجب تمرير كافة المعاملات وبنفس الترتيب.

يُمكننا تمرير معامل بقيمة مُسبقة عن طريق إعطاء المعامل القيمة التي نريدها عند تعريف الدالة. المثال التالي يُوضح ذلك:

x = 10 
y = 50
z = 30

def sum_triple(a,b,c=50):
result = a + b + c
return result

sum_triple(x,y)

لاحظ أننا أعطينا المعامل c قيمة تلقائية 50، وبذلك عند استدعاء الدالة نستطيع تجاهل هذا المعامل وعدم اعطاءه قيمة.

يُمكن تغيير أماكن المعاملات عند استدعاء الدالة وذلك عن طريق تحديد أسماء المعاملات واعطاءها القيم بطريقة صحيحة. انظر المثال التالي:

def sum_triple(a,b,c): 
result = a + b + c
return result

sum_triple(c=10,a=5,b=2)

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

تعريف الدوال بعدد غير محدد من المعاملات

نستطيع تعريف دالة تستقبل عدد غير محدد من المعاملات عن طريق *args و **kwargs كما في المثال التالي:

def sum(*args, **kwargs): 
print(args)
print(kwargs)

*args تعني عدد غير مُحدد من العوامل، و **kwargs تعني عدد غير محدد من العوامل المُسماة key word arguments.

ملاحظة هامة: عند تعريف دالة ما، يجب أن نبدأ بكتابة *args قبل كتابة **kwargs وإلا سيظهر لنا خطأ SyntaxError، وكذلك عند الاستدعاء، يجب أن نُمرر المعاملات غير المُسماة قبل المعاملات المُسماة.

يُوجد طريقة اخرى لاستدعاء الوظائف باستخدام args/kwargs وذلك عندما تكون المعطيات على شكل tuple أو قاموس كما يلي:

args = (1, 2, 3, 4)

kwargs = {"a": 3, "b": 4}

all_the_args(*args)            # equivalent to foo(1, 2, 3, 4)

all_the_args(**kwargs)         # equivalent to foo(a=3, b=4)

all_the_args(*args, **kwargs)  # equivalent to foo(1, 2, 3, 4, a=3, b=4)

يُمكننا إرجاع نتيجة من قيم متعددة على شكل tuple عند تعريف الدالة كما يلي:

def swap(x, y):
return y, x

x = 1
y = 2

x, y = swap(x, y)   

نطاق الدوال في بايثون

كما في لغات البرمجة المختلفة، مفهوم نطاق scope المتغيرات هو موضوع مهم في أي لغة برمجة. نعني بالنطاق هنا هو المكان/المجال الذي يكون فيه متغير ما مُتاحًا للوصول إليه. إذا عرَّفنا مجموعة متغيرات داخل دالة، فإن هذه المتغيرات يكون نطاقها داخل الدالة، ولا يُمكن الوصول لها من خارج الدالة إلا بطريقة معينة.

x = 5

def set_x(num):
    # المتغير المحلي يختلف عن المتغير في النطاق الواسع
    x = num    # => 43
    print(x)   # => 43

set_x(43)

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

def set_global_x(num):
    global x
    print(x)   # => 5
    x = num    # هذا المتغير يمثل المتغير على النطاق العام وقيمته الان 6
    print(x)   # => 6

set_x(43)
set_global_x(6)

الوحدات في بايثون

مكتبات بايثون
مكتبات بايثون

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

كيف نستورد مكتبة/وحدة في البايثون ؟

مثال، تتضمن البايثون وحدة معيارية مخصصة للعمليات الرياضية تُسمى math. المثال التالي يُوضح كيفية استيراد الوحدة عبر أمر import ومن ثم استدعاء دالة الجذر التربيعي sqrt منها:

import math

print(math.sqrt(16))  # => 4.0

يُمكننا استيراد دوال محددة من الوحدات التي نريد استخدامها. المثال التالي يُوضح كيفية استيراد دالتي ceil و floor من مكتبة math:

from math import ceil, floor

print(ceil(3.7))   # => 4.0

print(floor(3.7))  # => 3.0

يُمكننا استيراد جميع الدوال من الوحدة دفعة واحدة:

from math import *

ولكن هذه الطريقة لا يُنصح بها، وننصحك بأن تتعود على استيراد الدوال التي تحتاجها فقط.

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

import math as m

math.sqrt(16) == m.sqrt(16)  # => True

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

في الختام

 نتمنى أن نكون وُفقنا في إيصال المعلومة بالشكل الصحيح حول موضوع الدوال والوحدات في بايثون ونسعد بأي ملاحظة في التعليقات. كما نتمنى منكم مشاركة مقالات بايثونات في منصات التواصل الاجتماعي مثل تويتر وفيسبوك حتى تعم الفائدة.

6 Comments
  1. عدي ابوسعله القهالي says

    لو تكرمت يا دكتور نزل المكاتب الخاصه بالغة البايثون مع الدوال الخاصه بكل مكتبه مع عمل كل داله

اترك ردًا

Your email address will not be published.