View Categories

9.2. نطاقات ومساحات الأسماء في بايثون

5 دقيقة

9.2. نطاقات ومساحات الأسماء في بايثون #

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

لنبدأ ببعض التعريفات.

مساحة الأسماء هي ربط بين الأسماء والكائنات. تُطبّق معظم مساحات الأسماء حاليًا كقواميس بايثون، ولكن هذا عادةً لا يُلاحظ بأي شكل من الأشكال (باستثناء الأداء)، وقد يتغير في المستقبل. من أمثلة مساحات الأسماء: مجموعة الأسماء المُدمجة (التي تحتوي على دوال مثل abs() وأسماء الاستثناءات المُدمجة)؛ والأسماء العامة في الوحدة النمطية؛ والأسماء المحلية في استدعاء دالة. بمعنى ما، تُشكّل مجموعة سمات الكائن أيضًا مساحة اسم. من المهم معرفة مساحات الأسماء أنه لا توجد أي علاقة بين الأسماء في مساحات الأسماء المختلفة؛ على سبيل المثال، قد تُعرّف وحدتان مختلفتان دالة maxim دون أي لبس – يجب على مستخدمي الوحدات وضع بادئة لها باسم الوحدة.

بالمناسبة، أستخدم كلمة “سمة” لأي اسم بعد نقطة – على سبيل المثال، في التعبير z.real، real سمة للكائن z. بالمعنى الدقيق للكلمة، تُعدّ مراجع الأسماء في الوحدات مراجع سمات: في التعبير modname.funcname، modname هو كائن وحدة وfuncname سمة له. في هذه الحالة، يكون هناك ربط مباشر بين سمات الوحدة والأسماء العامة المُعرّفة فيها: فهما تشتركان في مساحة الاسم نفسها!

قد تكون السمات للقراءة فقط أو قابلة للكتابة. في الحالة الأخيرة، يُمكن تعيين السمات. سمات الوحدة قابلة للكتابة: يمكنك كتابة modname.the_answer = 42. يمكن أيضًا حذف السمات القابلة للكتابة باستخدام عبارة del. على سبيل المثال، سيؤدي del modname.the_answer إلى إزالة السمة the_answer من الكائن المسمى بواسطة modname.

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

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

النطاق هو منطقة نصية في برنامج بايثون حيث يُمكن الوصول إلى مساحة الأسماء مباشرةً. “يمكن الوصول إليها مباشرةً” هنا تعني أن مرجعًا غير مُؤهّل لاسم ما يحاول العثور على الاسم في مساحة الأسماء.

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

  • النطاق الأعمق، الذي يُبحث فيه أولاً، يحتوي على الأسماء المحلية.
  • نطاقات أي دوال مُحيطة، التي يُبحث فيها بدءًا من أقرب نطاق مُحيط، تحتوي على أسماء غير محلية، ولكن أيضًا غير عامة.
  • النطاق قبل الأخير يحتوي على الأسماء العامة للوحدة الحالية.
  • النطاق الأبعد (الذي يُبحث فيه أخيرًا) هو مساحة الأسماء التي تحتوي على الأسماء المُضمنة.

إذا تم إعلان اسم على أنه عالمي، فإن جميع المراجع والتعيينات تنتقل مباشرةً إلى النطاق الأوسط الذي يحتوي على الأسماء العامة للوحدة. لإعادة ربط المتغيرات الموجودة خارج النطاق الأعمق، يمكن استخدام العبارة nonlocal؛ إذا لم يتم إعلانها على أنها nonlocal، فإن هذه المتغيرات تكون للقراءة فقط (محاولة الكتابة إلى مثل هذا المتغير ستؤدي ببساطة إلى إنشاء متغير محلي جديد في النطاق الأعمق، مع ترك المتغير الخارجي الذي يحمل الاسم نفسه دون تغيير).

عادةً، يُشير النطاق المحلي إلى الأسماء المحلية للدالة الحالية (نصيًا). أما خارج الدوال، فيُشير النطاق المحلي إلى نفس مساحة الأسماء التي يُشير إليها النطاق العام: مساحة أسماء الوحدة النمطية. تُضيف تعريفات الفئات مساحة أسماء أخرى في النطاق المحلي.

من المهم إدراك أن النطاقات تُحدد نصيًا: فالنطاق العام للدالة المُعرّفة في الوحدة النمطية هو مساحة أسماء تلك الوحدة، بغض النظر عن مصدرها أو اسمها المستعار. من ناحية أخرى، يتم البحث الفعلي عن الأسماء ديناميكيًا، وقت التشغيل – ومع ذلك، يتطور تعريف اللغة نحو تحليل الأسماء الثابت، وقت “الترجمة”، لذا لا تعتمد على تحليل الأسماء الديناميكي! (في الواقع، تُحدد المتغيرات المحلية ثابتًا بالفعل).

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

يمكن استخدام العبارة global للإشارة إلى أن متغيرات معينة موجودة في النطاق العالمي ويجب أن تعود إليه؛ بينما تشير العبارة nonlocal إلى أن متغيرات معينة موجودة في نطاق مُغلق ويجب أن تعود إليه.

9.2.1. مثال على النطاقات ومساحات الأسماء #

هذا مثال يوضح كيفية الإشارة إلى النطاقات ومساحات الأسماء المختلفة، وكيف يؤثر كلٌّ من النطاق العام وغير المحلي على ربط المتغيرات:

def scope_test():

    def do_local():

        spam = "local spam"

     def do_nonlocal():

        nonlocal spam

        spam = "nonlocal spam"

     def do_global():

        global spam

        spam = "global spam" 

    spam = "test spam"

    do_local()

    print("After local assignment:", spam)

    do_nonlocal()

    print("After nonlocal assignment:", spam)

    do_global()

    print("After global assignment:", spam)

 scope_test()

print("In global scope:", spam)

ناتج الكود المثال هو:

After local assignment: test spam

After nonlocal assignment: nonlocal spam

After global assignment: nonlocal spam

In global scope: global spam

لاحظ كيف أن التعيين المحلي (وهو الافتراضي) لم يُغيّر ربط اختبار النطاق بالبريد العشوائي. غيّر التعيين غير المحلي ربط اختبار النطاق بالبريد العشوائي، وغيّرت التعيين العالمي الربط على مستوى الوحدة.

يمكنك أيضًا ملاحظة أنه لم يكن هناك أي ربط سابق للبريد العشوائي قبل التعيين العالمي.

error: Content is protected !!
Scroll to Top