الفصل السادس: الدوال – بناء وحدات برمجية قابلة لإعادة الاستخدام
مقدمة الفصل
عندما تبدأ بكتابة برامج أكبر، ستلاحظ أنك قد تكرر نفس الأوامر في أماكن مختلفة. هذا التكرار يجعل الكود طويلاً، صعب القراءة، وصعب الصيانة. مبدأ “لا تكرر نفسك” (Don’t Repeat Yourself - DRY) هو أحد أهم المبادئ في البرمجة.
الدوال (Functions) هي الأداة الأساسية لتطبيق هذا المبدأ. الدالة هي كتلة من الكود المنظم والقابل لإعادة الاستخدام، مصممة لأداء مهمة محددة. يمكنك التفكير فيها كـ “وصفة” أو “برنامج مصغر” يمكنك استدعاؤه باسمه في أي وقت لتنفيذ مهمته.
1. ما هي الدالة وكيف نعرّفها؟
لتعريف دالة في بايثون، نستخدم الكلمة المفتاحية def
.
البنية الأساسية:
def function_name():
# Code block to be executed
# This block must be indented
print("This is a function.")
def
: الكلمة التي تخبر بايثون أنك تقوم بتعريف دالة.function_name
: الاسم الذي تختاره للدالة (يتبع نفس قواعد تسمية المتغيرات).()
: الأقواس ضرورية، وقد تحتوي لاحقًا على “معاملات”.:
: النقطتان الرأسيتان اللتان تنهيان سطر التعريف.- الكتلة البرمجية (Code Block): كل الأسطر التي تلي التعريف بمسافة بادئة هي جزء من الدالة.
استدعاء الدالة (Calling the Function): لجعل الدالة تعمل، يجب عليك “استدعاؤها” باسمها متبوعًا بالأقواس.
# First, we define the function
def greet():
print("Welcome to Python!") # مرحباً بك في بايثون
# Now, we call the function to execute its code
greet()
greet() # We can call it multiple times
2. تمرير البيانات إلى الدوال (المعاملات)
لجعل الدوال أكثر فائدة، يمكننا تمرير بيانات إليها لتعمل عليها. هذه البيانات تسمى المعاملات (Parameters).
- المعامل (Parameter): هو المتغير الذي يُكتب داخل الأقواس عند تعريف الدالة.
- الوسيط (Argument): هو القيمة الفعلية التي تُمرر إلى الدالة عند استدعائها.
# 'name' is a parameter
def greet_user(name):
print(f"Hello, {name}!") # مرحباً يا {name}
# "Ahmed" and "Sara" are arguments
greet_user("Ahmed")
greet_user("Sara")
يمكن للدالة أن تأخذ أكثر من معامل واحد:
def user_info(name, age):
print(f"User: {name}, Age: {age}")
user_info("Ali", 30)
3. إعادة القيم من الدوال باستخدام return
في كثير من الأحيان، لا نريد أن تقوم الدالة بالطباعة على الشاشة فقط، بل نريدها أن تعيد قيمة يمكننا استخدامها في بقية البرنامج. لهذا نستخدم الكلمة المفتاحية return
.
الفرق الجوهري بين print
و return
:
print
: تعرض القيمة للمستخدم على الشاشة. إنها وظيفة إخراجية فقط.return
: تعيد القيمة إلى الكود الذي استدعى الدالة، مما يسمح لك بتخزينها في متغير أو استخدامها في عمليات أخرى.
# This function calculates the sum and returns it
def add_numbers(num1, num2):
result = num1 + num2
return result
# We call the function and store its output in a variable
sum_result = add_numbers(10, 5)
print(f"The result is: {sum_result}") # نطبع النتيجة التي تم إرجاعها
print(f"We can use it again: {sum_result * 2}") # يمكننا استخدامها في عمليات أخرى
بمجرد أن ينفذ المترجم سطر return
، تخرج الدالة فورًا من التنفيذ وتتجاهل أي كود يأتي بعدها داخل الدالة.
4. المعاملات ذات القيمة الافتراضية
يمكنك جعل معامل الدالة اختياريًا عن طريق تزويده بقيمة افتراضية. إذا لم يمرر المستخدم وسيطًا لهذا المعامل، فسيتم استخدام القيمة الافتراضية.
# 'country' has a default value
def user_profile(name, country="Unknown"):
print(f"Name: {name}, Country: {country}")
user_profile("Fatima") # سيتم استخدام القيمة الافتراضية
user_profile("John", "USA") # سيتم استخدام القيمة الممررة
5. نطاق المتغيرات (Variable Scope)
هذا مفهوم مهم جدًا. أي متغير يتم إنشاؤه داخل دالة يُعرف بأنه متغير محلي (local variable). هذا يعني أنه “يعيش” فقط داخل تلك الدالة ولا يمكن الوصول إليه من خارجها.
def my_function():
# 'x' is a local variable
x = 100
print(f"Inside the function, x is: {x}")
my_function()
# The following line will cause a NameError because 'x' does not exist outside the function
# print(f"Outside the function, x is: {x}")
هذا التصميم مفيد جدًا لأنه يمنع الدوال المختلفة من تعديل متغيرات بعضها البعض عن طريق الخطأ، مما يجعل برامجك أكثر أمانًا وموثوقية.
6. تمرين تطبيقي: آلة حاسبة منظمة
الآن، لنطبق ما تعلمناه عن الدوال في بناء برنامج عملي.
المطلوب:
بناء آلة حاسبة بسيطة تقوم بالعمليات الحسابية الأساسية (الجمع، الطرح، الضرب، القسمة). يجب أن يكون الكود منظمًا باستخدام الدوال.
إرشادات الحل:
- فكك المشكلة: بدلاً من وضع كل الكود في مكان واحد، قم بإنشاء دالة منفصلة لكل عملية حسابية (
add
,subtract
,multiply
,divide
). - حدد المدخلات والمخرجات: كل دالة من هذه الدوال يجب أن تأخذ رقمين كـ معاملات (
parameters
)، ويجب أن تعيد (return
) ناتج العملية. - عالج الحالات الخاصة: داخل دالة القسمة (
divide
)، تأكد من معالجة حالة القسمة على صفر. إذا كان المقام صفرًا، يجب أن تعيد الدالة رسالة خطأ مناسبة. - ابنِ الجزء الرئيسي من البرنامج:
- اعرض قائمة بالعمليات المتاحة للمستخدم.
- اطلب من المستخدم اختيار عملية.
- اطلب من المستخدم إدخال الرقمين.
- استخدم جمل
if/elif/else
للتحقق من اختيار المستخدم واستدعاء الدالة المناسبة. - قم بطباعة النتيجة النهائية التي أعادتها الدالة.
الحل المقترح:
# Function to add two numbers
def add(x, y):
return x + y
# Function to subtract two numbers
def subtract(x, y):
return x - y
# Function to multiply two numbers
def multiply(x, y):
return x * y
# Function to divide two numbers, with error handling
def divide(x, y):
if y == 0:
return "Error: Cannot divide by zero."
return x / y
# --- Main part of the program ---
print("Select an operation:")
print("1. Add")
print("2. Subtract")
print("3. Multiply")
print("4. Divide")
choice = input("Enter choice (1/2/3/4): ")
# Get user input and convert to numbers
try:
num1 = float(input("Enter first number: "))
num2 = float(input("Enter second number: "))
except ValueError:
print("Invalid input. Please enter numeric values.")
# We exit here because we can't proceed without valid numbers
exit()
# Call the appropriate function based on user choice
if choice == '1':
result = add(num1, num2)
print(f"{num1} + {num2} = {result}")
elif choice == '2':
result = subtract(num1, num2)
print(f"{num1} - {num2} = {result}")
elif choice == '3':
result = multiply(num1, num2)
print(f"{num1} * {num2} = {result}")
elif choice == '4':
result = divide(num1, num2)
print(f"{num1} / {num2} = {result}")
else:
print("Invalid choice.")
7. خلاصة الفصل
- الدوال تنظم الكود وتجعله قابلاً لإعادة الاستخدام، مما يسهل صيانته وتطويره.
- نستخدم الكلمة المفتاحية
def
لتعريف دالة جديدة. - المعاملات (Parameters) تسمح لنا بتمرير بيانات إلى الدوال لجعلها مرنة.
return
تسمح للدوال بإعادة قيمة يمكن استخدامها في أجزاء أخرى من البرنامج.- المتغيرات المحلية (Local Scope) تضمن أن المتغيرات تبقى معزولة داخل دوالها، مما يمنع التضارب.
ماذا بعد؟
الآن بعد أن أتقنت تنظيم الكود في وحدات منطقية، حان الوقت لنتعلم كيفية تنظيم البيانات نفسها. في الفصل السابع، سنغوص في عالم هياكل البيانات الأساسية في بايثون: القوائم، المجموعات، والقواميس.