فهم النطاق (Scope): الفرق بين المتغيرات المحلية والعالمية


فهم النطاق (Scope): الفرق بين المتغيرات المحلية والعالمية

ماذا سنتعلم؟

اليوم، سنتعمق في مفهوم النطاق (Scope) في البرمجة، ونفهم الفروقات الجوهرية بين المتغيرات المحلية (Local Variables) والمتغيرات العالمية (Global Variables) وكيفية التعامل معها بكفاءة.

الخطوة 1: المتغيرات العالمية (Global Variables)

المتغير العالمي هو متغير يتم تعريفه خارج أي دالة أو بلوك (block) من الكود، ويمكن الوصول إليه من أي مكان داخل البرنامج. لنرى مثالاً بسيطاً.

# تعريف متغير عالمي
global_message = "أنا رسالة عالمية!"

def display_global_message():
    # الدالة يمكنها الوصول إلى المتغير العالمي
    print(global_message)

display_global_message()

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

الخطوة 2: المتغيرات المحلية (Local Variables)

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

def create_local_message():
    # تعريف متغير محلي داخل الدالة
    local_message = "أنا رسالة محلية!"
    print(local_message)

create_local_message()
# محاولة الوصول إلى local_message من خارج الدالة ستسبب خطأ
# print(local_message) # هذا السطر سيؤدي إلى NameError

ملاحظة تقنية: المتغيرات المحلية تضمن عدم تداخل الأسماء وتحسين تنظيم الكود، حيث لا يمكن لدالة أخرى أن تعدل قيمتها عن طريق الخطأ.

الخطوة 3: التعامل مع المتغيرات العالمية داخل الدوال (الكلمة المفتاحية global)

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

global_counter = 0 # متغير عالمي

def increment_counter():
    global global_counter # الإعلان عن أننا سنعدل المتغير العالمي
    global_counter += 1 # تعديل قيمة المتغير العالمي
    print(f"العداد داخل الدالة: {global_counter}")

print(f"العداد قبل الاستدعاء: {global_counter}")
increment_counter()
print(f"العداد بعد الاستدعاء: {global_counter}")

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

الكود النهائي الكامل

إليك الكود كاملاً الذي يوضح جميع المفاهيم التي تعلمناها:

# المتغيرات العالمية (Global Variables)
global_message = "أنا رسالة عالمية!"
global_counter = 0

def display_global_message():
    # الدالة يمكنها الوصول إلى المتغير العالمي
    print(f"من الدالة display_global_message: {global_message}")

def create_local_message():
    # تعريف متغير محلي داخل الدالة
    local_message = "أنا رسالة محلية!"
    print(f"من الدالة create_local_message: {local_message}")
    # محاولة الوصول إلى global_message من هنا ممكنة أيضاً
    print(f"ويمكنني أيضاً الوصول إلى المتغير العالمي: {global_message}")

def increment_counter():
    global global_counter # الإعلان عن أننا سنعدل المتغير العالمي
    global_counter += 1 # تعديل قيمة المتغير العالمي
    print(f"العداد داخل الدالة increment_counter: {global_counter}")

# استدعاء الدوال
print("--- اختبار المتغيرات العالمية ---")
display_global_message()
print(f"من خارج الدالة: {global_message}")

print("\n--- اختبار المتغيرات المحلية ---")
create_local_message()
# السطر التالي سيسبب خطأ NameError إذا لم يكن معلقاً
# print(local_message)

print("\n--- اختبار تعديل المتغيرات العالمية ---")
print(f"العداد قبل الاستدعاء: {global_counter}")
increment_counter()
increment_counter()
print(f"العداد بعد الاستدعاءات: {global_counter}")

النتيجة المتوقعة

عند تشغيل السكربت أعلاه، ستكون النتيجة المطبوعة على الشاشة كالتالي:

--- اختبار المتغيرات العالمية ---
من الدالة display_global_message: أنا رسالة عالمية!
من خارج الدالة: أنا رسالة عالمية!

--- اختبار المتغيرات المحلية ---
من الدالة create_local_message: أنا رسالة محلية!
ويمكنني أيضاً الوصول إلى المتغير العالمي: أنا رسالة عالمية!

--- اختبار تعديل المتغيرات العالمية ---
العداد قبل الاستدعاء: 0
العداد داخل الدالة increment_counter: 1
العداد داخل الدالة increment_counter: 2
العداد بعد الاستدعاءات: 2