Skip to content

6. الوظائف

Image

6.1. البرنامج النصي [fonc_01]: نطاق المتغيرات

يُظهر البرنامج النصي [fonc_01] أمثلة على نطاق المتغيرات بين الدوال:


# نطاق المتغيرات
def f1():
    # يجب تجنب استخدام المتغيرات العالمية
    # المتغير العام i
    global i
    i += 1
    # المتغير المحلي j
    j = 10
    print(f"f1[i,j]=[{i},{j}]")


def f2():
    # يجب تجنب استخدام المتغيرات العالمية
    # المتغير العام i
    global i
    i += 1
    # المتغير المحلي j
    j = 20
    print(f"f2[i,j]=[{i},{j}]")


def f3():
    # المتغير المحلي i
    i = 1
    # المتغير المحلي j
    j = 30
    print(f"f3[i,j]=[{i},{j}]")


# البرنامج الرئيسي
i = 0
j = 0
# لن تكون هاتان المتغيرتان معروفتين لدالة f
# إلا إذا أعلنت الدالة صراحةً، باستخدام الأمر global، أنها تريد استخدامهما
# أو إذا كانت الدالة تستخدم المتغير العام للقراءة فقط
f1()
f2()
f3()
# j لم يتغير لكن i تغير
print(f"[i,j]=[{i},{j}]")

النتائج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_01.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]

Process finished with exit code 0

ملاحظات:

  • يُظهر البرنامج النصي استخدام المتغير i، المُعلن كمتغير عام في الدالتين f1 و f2. في هذه الحالة، يتشارك البرنامج الرئيسي والدالتين f1 و f2 نفس المتغير i.

6.2. البرنامج النصي [fonc_02]: نطاق المتغيرات

يستند البرنامج النصي [fonc_03] إلى البرنامج النصي [fonc_02] ويوضح كيفية تجنب استخدام المتغيرات العامة:


# نطاق المتغيرات
def f1(i):
    # المتغير المحلي i
    i += 1
    # المتغير المحلي j
    j = 10
    print(f"f1[i,j]=[{i},{j}]")
    # نقوم بإرجاع القيمة المعدلة
    return i


def f2(i):
    # المتغير المحلي i
    i += 1
    # المتغير المحلي j
    j = 20
    print(f"f2[i,j]=[{i},{j}]")
    # يتم إرجاع القيمة المعدلة
    return i


def f3():
    # المتغير المحلي i
    i = 1
    # المتغير المحلي j
    j = 30
    print(f"f3[i,j]=[{i},{j}]")


# البرنامج الرئيسي
i = 0
j = 0
# لن تكون هاتان المتغيرتان معروفتين لدالة f
# إلا إذا أعلنت هذه الدالة صراحةً باستخدام الأمر global أنها تريد استخدامهما
# أو إذا كانت الدالة تستخدم المتغير العام للقراءة فقط
i = f1(i)
i = f2(i)
f3()
# لم يتغير j لكن i تغير
print(f"[i,j]=[{i},{j}]")

تعليقات:

  • السطران 2 و12: بدلاً من إعلان المتغير [i] كمتغير عام، يتم تمريره كمعلمة إلى الدالتين f1 وf2؛
  • السطران 9 و19: تقوم الدالتان f1 وf2 بإرجاع المتغير [i] بعد تعديله إلى البرنامج الرئيسي. ويسترد البرنامج الرئيسي هذا المتغير في السطرين 36 و37؛

النتائج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_02.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]

Process finished with exit code 0

6.3. البرنامج النصي [fonc_03]: نطاق المتغيرات

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


def f1():
    # هنا المتغير العام i معروف
    print(f"[f1] i={i}")
    # هنا المتغير العام j معروف
    print(f"[f1] j={j}")


def f2():
    # هنا المتغير العام i غير معروف
    # لأن الدالة f2 تُعرّف متغيرًا محليًّا يحمل نفس الاسم
    # وبالتالي فإن لها الأولوية
    try:
        # محاولة عرض المتغير المحلي i المُعرَّف لاحقًا
        print(f"[f2] i={i}")
        # التعليمة التالية تجعل من i متغيرًا محليًا للدالة f2
        i = 7
    except BaseException as erreur:
        print(f"[f2] erreur={erreur}")


def f3():
    # هنا، المتغير العام i غير معروف
    # لأن الدالة f3 تُعرِّف متغيرًا محليًّا يحمل نفس الاسم
    # وبالتالي فإن لها الأولوية

    # التعليمة التالية تجعل من i متغيرًا محليًّا
    i = 7
    # عرض - هنا تكون i معروفة
    print(f"[f3] i={i}")


# main -----------
# المتغيرات العالمية للدوال
i = 10
j = 20
# استدعاء f1
f1()
print(f"[main] i={i}, j={j}")
# استدعاء f2
f2()
print(f"[main] i={i}")
# استدعاء f3
f3()
print(f"[main] i={i}")

ملاحظات

  • السطر 34: يحدد الكود الرئيسي متغيرًا [i]؛
  • الأسطر 1-5: تستخدم الدالة f1 أيضًا متغيرًا [i] دون تعيين قيمة له. وهذا يمثل قراءة للمتغير [i]. في هذه الحالة، المتغير [i] المستخدم هو المتغير الموجود في الكود المستدعي، السطر 34؛
  • الأسطر 8-18: تستخدم الدالة f2 أيضًا متغيرًا [i] ولكنها تُعيّن له قيمة في السطر 16. إن تعيين قيمة للمتغير [i] في f2 يجعل تلقائيًّا المتغير [i] متغيرًا محليًّا للدالة [f2]. وبالتالي، فإن هذه الدالة «تخفي» المتغير [i] من الكود المستدعي؛
  • السطر 14: ستفشل عملية كتابة المتغير المحلي [i] لأن هذا المتغير لا يحتوي على قيمة عند الوصول إلى السطر 14. ويحصل على قيمته في السطر 16. وستحدث استثناء. ولهذا السبب، تم إدراج السطر 14 في عبارة try / catch؛
  • الأسطر 21-29: تقوم الدالة f3 بنفس ما تقوم به الدالة f2، لكنها تُعرِّف متغيرها المحلي [i] في وقت أبكر؛

النتائج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_03.py
[f1] i=10
[f1] j=20
[main] i=10, j=20
[f2] erreur=local variable 'i' referenced before assignment
[main] i=10
[f3] i=7
[main] i=10

Process finished with exit code 0

6.4. البرنامج النصي [fonc_04]: طريقة تمرير المعلمات

النص البرمجي هو كما يلي:


# الدالة f1
def f1(a):
    a = 2


# الدالة f2
def f2(a, b):
    a = 2
    b = 3
    return a, b


# ------------------------ main
x = 1
f1(x)
print(f"x={x}")
(x, y) = (-1, -1)
(x, y) = f2(x, y)
print(f"x={x}, y={y}")

النتائج

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_04.py
x=1
x=2, y=3

Process finished with exit code 0

ملاحظات:

  • كل شيء في لغة Python هو كائن. وتُسمى بعض الكائنات «ثابتة» (بالإنجليزية): لا يمكن تعديلها. وهذا هو الحال بالنسبة للأرقام وسلاسل الأحرف والمجموعات. وعندما يتم تمرير كائنات Python كمعلمات إلى الدوال، يتم تمرير مراجعها ما لم تكن هذه الكائنات «ثابتة»، وفي هذه الحالة يتم تمرير قيمة الكائن؛
  • تهدف الدالتان f1 (السطر 2) و f2 (السطر 7) إلى توضيح تمرير معلمة إخراج. نريد أن يتم تعديل المعلمة الفعلية للدالة بواسطة الدالة نفسها؛
  • السطران 2-3: تقوم الدالة f1 بتعديل معلمتها الشكلية a. نريد معرفة ما إذا كان المعلم الفعلي سيتغير هو الآخر؛
  • السطران 14-15: المعلمة الفعلية هي x=1. ويُظهر السطر 2 من النتائج أن المعلمة الفعلية لم تتغير. وبالتالي، فإن المعلمة الفعلية x والمعلمة الشكلية a هما كيانان مختلفان؛
  • السطور 8-10: تقوم الدالة f2 بتعديل معلمتيها الشكليتين a و b، وتعيدهما كنتائج؛
  • السطور 17-18: يتم تمرير المعلمات الفعلية (x، y) إلى f2، ويتم إعادة نتيجة f2 إلى (x، y). يوضح السطر 3 من النتائج أن المعلمات الفعلية (x، y) قد تم تعديلها.

ونستنتج من ذلك أنه عندما تكون الكائنات «غير القابلة للتغيير» معلمات إخراج، يجب أن تكون جزءًا من النتائج التي ترجعها الدالة.

6.5. البرنامج النصي [fonc_05]: ترتيب كتابة الدوال في البرنامج النصي

يوضح البرنامج النصي [fonc_05] أنه لا يمكن استدعاء دالة ما لم تكن قد وردت سابقًا في الكود:


# ------------------------ main
print(f2(100, 200))

# الدالة f1
def f1(a):
    return a + 10


# الدالة f2
def f2(a, b):
    return f1(a + b)

ملاحظات

  • السطر 2 سيؤدي إلى حدوث خطأ لأنه يستخدم الدالة f2 التي لم يتم تعريفها بعد في البرنامج النصي؛

النتائج

1
2
3
4
5
6
7
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_05.py
Traceback (most recent call last):
  File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_05.py", line 2, in <module>
    print(f2(100, 200))
NameError: name 'f2' is not defined

Process finished with exit code 1

6.6. النص البرمجي [fonc_06]: ترتيب كتابة الدوال في النص البرمجي

يوضح البرنامج النصي [fonc_06] أن ما ينطبق على الكود المستدعي لا ينطبق على الدوال:


# الدالة f2
def f2(a, b):
    return f1(a + b)


# الدالة f1
def f1(a):
    return a + 10


# ------------------------ الرئيسي
print(f2(100, 200))

ملاحظات

  • السطر 3: تستخدم الدالة [f2] الدالة [f1] المُعرَّفة لاحقًا في البرنامج النصي. ومع ذلك، لا يتسبب هذا في حدوث أي خطأ. وبالتالي، يمكننا استنتاج أن ترتيب تعريف الدوال في برنامج نصي بلغة Python لا يهم؛

النتائج

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_06.py
310

Process finished with exit code 0

6.7. النص البرمجي [fonc_07]: استخدام الوحدات النمطية

يوضح البرنامج النصي [fonc_07] كيفية عزل الدوال في وحدة نمطية.

Image

نقوم بعزل الوظائف القابلة لإعادة الاستخدام في وحدة نمطية. بدلاً من نقلها من سكريبت إلى آخر:

  • نضعها في ملف منفصل نعلن عنه بطريقة معينة؛
  • تقوم البرامج النصية التي تحتاج إلى هذه الوظائف بـ«استيراد» الوحدة النمطية التي تحتوي عليها؛

النص البرمجي [fonctions_module_01] هو كما يلي:


# الدالة f2
def f2(a, b):
    return f1(a + b)

# الدالة f1
def f1(a):
    return a + 10

لكي تتمكن البرامج النصية الأخرى من الإشارة إلى وظائف البرنامج النصي [fonctions_module_01]، هناك طرق مختلفة للقيام بذلك. وتختلف هذه الطرق حسب ما إذا كان البرنامج النصي يُنفَّذ داخل [PyCharm] أم لا.

في [PyCharm يتم البحث عن الوحدات المستوردة في مجلدات محددة تسمى [Sources Root]. هناك طريقتان لتحويل مجلد إلى [Sources Root]:

Image

  • في [4]، يتغير لون المجلد؛

بعد هذه العملية، يتم التعرف على المجلد [fonctions/modules] كمجلد مصدر. يمكن عندئذٍ كتابة ما يلي في البرنامج النصي:

from fonctions_module_01 import f2

لاستيراد/استخدام الدالة f2 المُعرَّفة في الوحدة النمطية [fonctions_module_01.py].

هناك طريقة أخرى تتمثل في استخدام خصائص المشروع:

  • فيما سبق، تسمح التسلسلات [1-6] بتحويل المجلد [shared] إلى مجلد لتخزين الوحدات النمطية المراد استيرادها؛

ولن نقوم في الوقت الحالي بتعيين أي مجلد مثل [Sources Root] باستثناء المجلد الجذر للمشروع:

Image

وبعد ذلك، يمكننا كتابة البرنامج النصي [fonc-07] التالي:


# استخدام الوحدات النمطية
import sys

# ------------------------ الرئيسي
print(f"Python path={sys.path}")
from fonctions.shared.fonctions_module_01 import f2

print(f2(100, 200))
  • السطر 2: يتم استيراد الكائن [sys] حتى يتسنى استخدام السطر 5، وهو السمة [path] التي تُعطي ما يُسمى بـ [Python Path]: قائمة بالمجلدات التي سيتم استكشافها بحثًا عن الوحدات المستوردة؛
  • السطر 6: يتم استيراد الدالة f2 من الوحدة النمطية [fonctions_module_01]. للإشارة إلى هذه الوحدة النمطية، نستخدم المسار الذي يربط جذر المشروع بالوحدة النمطية. في Pycharm، يكون جذر المشروع دائمًا جزءًا من المجلدات التي يتم استكشافها عند البحث عن وحدة نمطية مستوردة في نص برمجي. وبالتالي، فإن هذا المجلد جزء من [Python Path] الخاص بالمشروع. وهذا ما سيسمح لنا السطر 5 بالتحقق منه؛
  • السطر 6: إذا كنا سنصف المسار الذي يؤدي من جذر المشروع إلى المجلد [fonctions_module_01]، فسنكتب [fonctions/shared/fonctions_module_01]. في مسار الوحدة النمطية، يتم استبدال علامة / بالنقطة. لذا نكتب [fonctions.modules.fonctions_module_01]؛
  • بعد السطر 6، تصبح الدالة f2 معروفة. ونستخدمها في السطر 8؛

النتائج


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_07.py
Python path=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
310

Process finished with exit code 0

أعلاه:

  • المظللة باللون الأخضر، نرى أن جذر المشروع جزء من [Python Path]؛
  • المظلل باللون الأصفر، نرى أن مجلد البرنامج النصي الذي تم تنفيذه يشكل أيضًا جزءًا من [Python Path]؛
  • العناصر الأخرى في [Python Path] تأتي مباشرةً من مجلد تثبيت Python؛

ماذا يحدث عندما لا نستخدم PyCharm لتنفيذ [fonc-07]؟

Image

Image

  • في [1]، يتم تشغيل البرنامج النصي [fonc-07]. ونكون موجودين في مجلد [fonctions]؛
  • في [2]، نلاحظ أن مجلد التنفيذ جزء من [Python Path]. والأمر كذلك دائمًا. ويمكننا أيضًا ملاحظة أن المجلد الجذر [C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020] ليس جزءًا من [Python Path
  • في [3]، يُعلن مترجم Python أنه لا يجد الوحدة النمطية [fonctions]؛

للبحث عن الوحدة المستوردة [fonctions.shared.fonctions_module_01]، يبحث مترجم Python في مجلدات [Python Path] عن مجلد فرعي باسم [fonctions]. ولكنه لا يجده في أي مكان. ذلك أن المجلد الفرعي [fonctions] موجود ضمن المجلد [C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020] الذي لا ينتمي إلى المجلد [Python Path].

يقدم البرنامج النصي [fonc-08] حلاً محتملاً لهذه المشكلة.

6.8. البرنامج النصي [fonc_08]: إضافة مجلدات إلى [Python Path]

يمكن تعديل ملف [Python Path] برمجيًا كما يوضح البرنامج النصي [fonc-08]:


# استخدام الوحدات النمطية
import os
import sys

# مجلد البرنامج النصي
script_dir = os.path.dirname(os.path.abspath(__file__))
# مسار Python قبل التعديل
print(f"Python path avant={sys.path}")
# إضافة المجلد [shared] إلى مسار Python
sys.path.append(f"{script_dir}/shared")
# مسار Python بعد التعديل
print(f"Python path après={sys.path}")

# استيراد f2
from fonctions_module_01 import f2

# ------------------------ main
print(f2(100, 200))

ملاحظات

  • السطر 4: المتغير الخاص [__file__] هو اسم البرنامج النصي الذي يتم تنفيذه. وفقًا لسياق التنفيذ، قد يكون هذا الاسم مطلقًا (Pycharm) أو نسبيًا (وحدة التحكم). تُرجع الدالة [os.path.abspath] الاسم المطلق للملف الذي يتم تمرير اسمه إليها. تُرجع الدالة [os.path.dirname] الاسم المطلق للمجلد الذي يحتوي على الملف الذي يتم تمرير اسمه إليها؛
  • السطر 10: [sys.path] هو مصفوفة تحتوي على أسماء المجلدات التي يجب استكشافها عند البحث عن وحدة نمطية. تُضاف إلى هذه المصفوفة جذر المشروع المحدد في السطر 4؛
  • يتم عرض [Python Path] قبل (السطر 8) وبعد (السطر 12) التعديل؛
  • السطر 15: يتم استيراد الوحدة النمطية [fonctions_module_01] التي تحتوي على الدالة f2؛

يؤدي التنفيذ في PyCharm إلى النتائج التالية:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310

Process finished with exit code 0
  • السطر 3: نلاحظ أن الملف [shared] موجود مرتين في الملف [Python Path]. يمكن تجنب ذلك، لكنه لا يشكل مشكلة في هذه الحالة؛
  • السطر 4: تم تنفيذ الدالة f2 بنجاح؛

الآن لنقم بتنفيذ [fonc-08] في محطة طرفية:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions>python fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
  • السطر 2: كما سبق، المجلد [shared] غير موجود في [Python Path]؛
  • السطر 3: الآن أصبح موجودًا فيه؛
  • السطر 4: تم العثور على الدالة f2؛

6.9. البرنامج النصي [fonc_09]: إعلان نوع المعلمات

يُظهر البرنامج النصي [fonc_09] أنه يمكن إعلان نوع معلمات الدالة وكذلك نوع النتيجة. ومع ذلك، فإن هذا الإعلان لا يفيد إلا في توثيق الدالة. لا يتحقق مترجم Python من أن المعلمات الفعلية للدالة هي بالفعل من النوع المتوقع. ومع ذلك، يشير Pycharm إلى عدم اتساق الأنواع بين المعلمات الفعلية والشكلية. وهذا السبب وحده كافٍ لجعل إعلانات الأنواع أمرًا لا غنى عنه.

النص البرمجي هو كما يلي:


# دالة مع تحديد نوع المعلمات
# هذا يُستخدم كوثيقة إرشادية فقط لأن مترجم بايثون لا يأخذها في الاعتبار


def show(param: int) -> int:
    print(f"param={param}, type(param)={type(param)}")
    return param + 1


# main -------------------------
print(show(4))
show("xyz")

ملاحظات:

  • السطر 5: نعلن أن المعلمة الشكلية [param] من النوع [int] وأن نتيجة الدالة هي أيضًا من النوع [int]؛
  • السطر 11: المعلمة الفعلية للدالة [show] من النوع الصحيح؛
  • السطر 12: المعلمة الفعلية للدالة [show] ليست من النوع الصحيح؛

النتائج

C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_09.py
param=4, type(param)=<class 'int'>
5
param=xyz, type(param)=<class 'str'>
Traceback (most recent call last):
  File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_09.py", line 11, in <module>
    show("xyz")
  File "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_09.py", line 6, in show
    return param + 1
TypeError: can only concatenate str (not "int") to str

Process finished with exit code 1
  • السطر 10: نوع المعلمة [param] هو [str]. عند ظهور هذه الرسالة، نكون قد دخلنا بالفعل إلى كود الدالة [show]. وبالتالي، فقد قبل مترجم Python أن يكون النوع الفعلي للمعلمة الخاصة بالدالة [show] هو [str]؛
  • السطر 7 من الكود يتسبب في الاستثناء الذي تعكسه الأسطر 4-10 من النتائج؛

ومع ذلك، تشير PyCharm إلى وجود خطأ:

Image

في [1]، أبرز PyCharm الاستدعاء الخاطئ.

6.10. نص برمجي [fonc_10]: المعلمات المسماة

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


# يمكن الإشارة إلى المعلمات الفعلية بأسمائها الشكلية
def f(x, y):
    return x + y


# main
print(f(y=10, x=3))

ملاحظات

  • السطر 2: الدالة f لها معلمتان رسميتان هما x و y؛
  • السطر 7: عند استدعاء الدالة f، يمكن استخدام أسماء المعلمات الشكلية. قد تكون هذه الممارسة مفيدة في حالتين على الأقل:
    • تحتوي الدالة على العديد من المعلمات التي يكون لمعظمها قيمة افتراضية. عند الاستدعاء، تسمح التقنية السابقة بتهيئة المعلمات التي لا نريد استخدام قيمتها الافتراضية فقط؛
    • إذا كانت المعلمات الشكلية تحمل أسماء ذات معنى، فإن استخدام المعلمات المسماة عند استدعاء الدالة يحسّن قابلية قراءة الكود؛

النتائج

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_10.py
13

Process finished with exit code 0

6.11. النص البرمجي [fonc_11]: دالة متكررة

النص البرمجي [fonc_11] هو مثال على دالة متكررة (تستدعي نفسها):


# دالة متكررة
def fact(i: int) -> int:
    # العدد التوافقي (1) يساوي 1
    # يجب أن تنتهي الدالة التكرارية في وقت ما
    if i == 1:
        return 1
    else:
        # العدد التوافقي(i) = i * العدد التوافقي(i-1)
        return i * fact(i - 1)


# ---------- main
print(f"fact(8)={fact(8)}")

تعليقات

  • الأسطر 1-9: دالة المضروب؛
  • السطر 9: الدالة [factorielle] تستدعي نفسها؛
  • الأسطر 5-6: يجب أن تتوقف الدالة التكرارية دائمًا عند استيفاء شرط ما، وإلا فسيحدث تكرار لانهائي؛

النتائج

1
2
3
4
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_11.py
fact(8)=40320

Process finished with exit code 0

6.12. نص برمجي [fonc_12]: دالة متكررة

تقدم الدالة [fonc_12] مزيدًا من التفاصيل حول كيفية عمل التكرار:


# دالة متكررة
# سلوك المعلمة j


def fact(i: int, j: int) -> int:
    # توقف الدالة التكرارية
    if i == 1:
        print(f"j={j}")
        return 1
    else:
        # معالجة j
        j += 1
        print(f"avant fact j={j}")
        # التكرار
        f = fact(i - 1, j)
        print(f"après fact j={j}")
        # النتيجة
        return i * f


# ---------- main
print(f"fact(8)={fact(8, 0)}")

تعليقات

  • السطر 5: ما زلنا نركز على دالة المضروب. نضيف إليها المعلمة [j]؛
  • السطر 12: يتم زيادة المتغير j بانتظام عند كل حساب لـ «العامل» (العدد التربيعي). نعرض قيمته قبل (السطر 12) وبعد (السطر 16) عملية التكرار (السطر 15)؛

النتائج

C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_12.py
avant fact j=1
avant fact j=2
avant fact j=3
avant fact j=4
avant fact j=5
avant fact j=6
avant fact j=7
j=7
après fact j=7
après fact j=6
après fact j=5
après fact j=4
après fact j=3
après fact j=2
après fact j=1
fact(8)=40320

Process finished with exit code 0
  • الأسطر 2-8: نلاحظ أن قيمة [j] تزداد طالما استمرت التكرارية حتى تلبية الشرط الذي يتوقف عنده التكرار. ومنذ تلك اللحظة، تتم عودة استدعاءات الدالة [fact] في الاتجاه المعاكس للاستدعاءات؛
  • الأسطر 10-16: تعكس هذه العروض عمليات العودة المتتالية لاستدعاء دالة العدد التوافقي. تستعيد المتغير [j] قيمها حتى تصل إلى قيمتها الأولية 1؛