الفرق بين المراجعتين لصفحة: «Python/scopes-and-namespaces»
طلا ملخص تعديل |
لا ملخص تعديل |
||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:مجالات الأسماء والنطاقات في بايثون}}</noinclude> | <noinclude>{{DISPLAYTITLE:مجالات الأسماء والنطاقات في بايثون}}</noinclude> | ||
مجال الأسماء هو رابط بين الأسماء والكائنات، وتستخدم معظم مجالات الأسماء في الوقت الحاضر [[Python/dict|كقواميس]]. ومن الأمثلة على مجالات الأسماء: مجموعة الأسماء الداخلية (وتتضمن الدوال مثل <code>abs()</code>، وأسماء الاستثناءات الداخلية)، والأسماء العامة (global) في وحدة معينة، والأسماء المحلية (local) في بنية دالّة ما. إضافة إلى ما سبق، يمكننا أن نعدّ مجموعة خاصيات (attributes) كائن معيّن مجالًا للأسماء أيضًا. | مجال الأسماء هو رابط بين الأسماء والكائنات، وتستخدم معظم مجالات الأسماء في الوقت الحاضر [[Python/dict|كقواميس]]. ومن الأمثلة على مجالات الأسماء: مجموعة الأسماء الداخلية (وتتضمن الدوال مثل <code>[[Python/abs|abs()]]</code>، وأسماء الاستثناءات الداخلية)، والأسماء العامة (global) في وحدة معينة، والأسماء المحلية (local) في بنية دالّة ما. إضافة إلى ما سبق، يمكننا أن نعدّ مجموعة خاصيات (attributes) كائن معيّن مجالًا للأسماء أيضًا. | ||
والمقصود بالخاصيات هنا كل ما يأتي بعد النقطة، فعلى سبيل المثال في التعبير <code>z.real</code> تعدّ <code>real</code> خاصية للكائن <code>z</code>. كذلك تعدّ الإشارات إلى الأسماء في الوحدات إشارات للخاصيات، ففي التعبير <code>modname.funcname</code>، تكون <code>modname</code> كائن وحدة و<code>funcname</code> خاصّية له. | والمقصود بالخاصيات هنا كل ما يأتي بعد النقطة، فعلى سبيل المثال في التعبير <code>z.real</code> تعدّ <code>real</code> خاصية للكائن <code>z</code>. كذلك تعدّ الإشارات إلى الأسماء في [[Python/modules|الوحدات]] إشارات للخاصيات، ففي التعبير <code>modname.funcname</code>، تكون <code>modname</code> كائن وحدة و<code>funcname</code> خاصّية له. | ||
إنّ أهمّ ما يجب معرفته عن مجالات الأسماء هو عدم وجود أي علاقة تربط بين الأسماء في مجالات الأسماء المختلفة، فعلى سبيل المثال، يمكن [[Python/modules|لوحدتين]] مختلفتين أن تعرّفا دالة باسم <code>maximize</code> دون حدوث أيّ تضارب، ولكن يجب إضافة اسم الوحدة قبل اسم الدالة عند استخدامها في الشيفرة البرمجية. | إنّ أهمّ ما يجب معرفته عن مجالات الأسماء هو عدم وجود أي علاقة تربط بين الأسماء في مجالات الأسماء المختلفة، فعلى سبيل المثال، يمكن [[Python/modules|لوحدتين]] مختلفتين أن تعرّفا دالة باسم <code>maximize</code> دون حدوث أيّ تضارب، ولكن يجب إضافة اسم الوحدة قبل اسم الدالة عند استخدامها في الشيفرة البرمجية. | ||
سطر 8: | سطر 8: | ||
في هذه الحالة هناك رابط مباشر بين خاصيات الوحدة والأسماء العامة والمعرّفة في [[Python/modules|الوحدة]]، وهو أنّها تشترك مع بعضها البعض بمجال أسماء واحد. | في هذه الحالة هناك رابط مباشر بين خاصيات الوحدة والأسماء العامة والمعرّفة في [[Python/modules|الوحدة]]، وهو أنّها تشترك مع بعضها البعض بمجال أسماء واحد. | ||
تنشأ مجالات الأسماء في أوقات مختلفة وتمتلك أعمارًا مختلفة أيضًا. فمجال الأسماء الذي يضمّ الأسماء الداخلية ينشأ عند بدء تشغيل [[Python/interpreter|مفسّر بايثون]] ولا يُحذف على الإطلاق. أما | تنشأ مجالات الأسماء في أوقات مختلفة وتمتلك أعمارًا مختلفة أيضًا. فمجال الأسماء الذي يضمّ الأسماء الداخلية ينشأ عند بدء تشغيل [[Python/interpreter|مفسّر بايثون]] ولا يُحذف على الإطلاق. أما مجال الأسماء العام الخاص [[Python/modules|بوحدة]] معينة فينشأ عند تعريف تلك [[Python/modules|الوحدة]] ضمن الشيفرة، وعادة ما يبقى مجال الأسماء هذا إلى حين إغلاق مفسّر بايثون. | ||
تكون الشيفرات البرمجية المنفّذة بواسطة الاستدعاء ذي المستوى العالي (top-level invocation) في مفسّر بايثون، سواء أكان مصدر هذه الشيفرات ملف مستقلًّا أو ضمن المفسّر نفسه، جزءًا من وحدة تدعى <code>__main__</code>؛ لذا تمتلك هذه الشيفرات مجال أسماء عام، وكذلك الأمر بالنسبة للأسماء الداخلية، إذ أنّها جزء من وحدة خاصة تحمل الاسم <code>builtins</code>. | تكون الشيفرات البرمجية المنفّذة بواسطة الاستدعاء ذي المستوى العالي (top-level invocation) في مفسّر بايثون، سواء أكان مصدر هذه الشيفرات ملف مستقلًّا أو ضمن المفسّر نفسه، جزءًا من وحدة تدعى <code>__main__</code>؛ لذا تمتلك هذه الشيفرات مجال أسماء عام، وكذلك الأمر بالنسبة للأسماء الداخلية، إذ أنّها جزء من وحدة خاصة تحمل الاسم <code>builtins</code>. | ||
سطر 20: | سطر 20: | ||
وبالرغم من أن النطاقات تحدّد بطريقة سكونية، إلا إنّها تستخدم بطريقة ديناميكية. ففي أي لحظة من لحظات تنفيذ الشيفرة، هناك ما لا يقل عن ثلاثة مجالات متداخلة يمكن الوصول إلى مجالات الأسماء فيها بصورة مباشرة: | وبالرغم من أن النطاقات تحدّد بطريقة سكونية، إلا إنّها تستخدم بطريقة ديناميكية. ففي أي لحظة من لحظات تنفيذ الشيفرة، هناك ما لا يقل عن ثلاثة مجالات متداخلة يمكن الوصول إلى مجالات الأسماء فيها بصورة مباشرة: | ||
* النطاق الداخلي، والذي يجري فيه البحث أوّلًا، ويضمّ الأسماء المحلية | * النطاق الداخلي، والذي يجري فيه البحث أوّلًا، ويضمّ الأسماء المحلية. | ||
* النطاقات الخاصّة بأي دالة محيطة، والتي يجري البحث فيها بدءًا من أقرب نطاق محيط، تضمّ أسماء غير محلّية ولكن غير عامّة أيضًا | * النطاقات الخاصّة بأي دالة محيطة، والتي يجري البحث فيها بدءًا من أقرب نطاق محيط، تضمّ أسماء غير محلّية ولكن غير عامّة أيضًا. | ||
* يضمّ النطاق ما قبل الأخير الأسماء العامّة للوحدة الحالية. | * يضمّ النطاق ما قبل الأخير الأسماء العامّة للوحدة الحالية. | ||
* النطاق الخارجي (يجري البحث فيه آخرًا) وهو مجال الأسماء الذي يضمّ الأسماء الداخلية | * النطاق الخارجي (يجري البحث فيه آخرًا) وهو مجال الأسماء الذي يضمّ الأسماء الداخلية | ||
سطر 34: | سطر 34: | ||
من جهة أخرى، يجري البحث عن الأسماء بصورة ديناميكية في وقت التشغيل، ولكن اللغة تتّجه بصورة تدريجية إلى تمييز الأسماء سكونيًا، أي في وقت التصريف (complie)؛ لذا لا تعتمد على عملية تمييز الأسماء الديناميكية. (في الواقع، المتغيرات المحلية تحدّد بصورة سكونية). | من جهة أخرى، يجري البحث عن الأسماء بصورة ديناميكية في وقت التشغيل، ولكن اللغة تتّجه بصورة تدريجية إلى تمييز الأسماء سكونيًا، أي في وقت التصريف (complie)؛ لذا لا تعتمد على عملية تمييز الأسماء الديناميكية. (في الواقع، المتغيرات المحلية تحدّد بصورة سكونية). | ||
تختلف بايثون عن غيرها من اللغات في أنّه | تختلف بايثون عن غيرها من اللغات في أنّه عند غياب عبارة عامة فإنّ عمليات الإسناد إلى الأسماء تذهب إلى النطاق الداخلي، ويجب الانتباه إلى أن عمليات الإسناد لا تنسخ البيانات، وإنّما تربط الأسماء بالكائنات، وهذا الأمر ينطبق أيضًا على عملية الحذف، فعبارة <code>del x</code> تقطع الرابط بين <code>x</code> وبين مجال الأسماء المشار إليه عن طريق النطاق المحلي. | ||
في الواقع تستخدم جميع العمليات التي تقدّم أسماء جديدة النطاقَ المحلي، وعلى وجه الخصوص تعمل عبارات <code>import</code> [[Python/defining-functions|وتعاريف الدوال]] على ربط [[Python/modules|الوحدات]] أو اسم الدالة في النطاق المحلي. | في الواقع تستخدم جميع العمليات التي تقدّم أسماء جديدة النطاقَ المحلي، وعلى وجه الخصوص تعمل عبارات <code>import</code> [[Python/defining-functions|وتعاريف الدوال]] على ربط [[Python/modules|الوحدات]] أو اسم الدالة في النطاق المحلي. |
مراجعة 12:55، 18 مايو 2018
مجال الأسماء هو رابط بين الأسماء والكائنات، وتستخدم معظم مجالات الأسماء في الوقت الحاضر كقواميس. ومن الأمثلة على مجالات الأسماء: مجموعة الأسماء الداخلية (وتتضمن الدوال مثل abs()
، وأسماء الاستثناءات الداخلية)، والأسماء العامة (global) في وحدة معينة، والأسماء المحلية (local) في بنية دالّة ما. إضافة إلى ما سبق، يمكننا أن نعدّ مجموعة خاصيات (attributes) كائن معيّن مجالًا للأسماء أيضًا.
والمقصود بالخاصيات هنا كل ما يأتي بعد النقطة، فعلى سبيل المثال في التعبير z.real
تعدّ real
خاصية للكائن z
. كذلك تعدّ الإشارات إلى الأسماء في الوحدات إشارات للخاصيات، ففي التعبير modname.funcname
، تكون modname
كائن وحدة وfuncname
خاصّية له.
إنّ أهمّ ما يجب معرفته عن مجالات الأسماء هو عدم وجود أي علاقة تربط بين الأسماء في مجالات الأسماء المختلفة، فعلى سبيل المثال، يمكن لوحدتين مختلفتين أن تعرّفا دالة باسم maximize
دون حدوث أيّ تضارب، ولكن يجب إضافة اسم الوحدة قبل اسم الدالة عند استخدامها في الشيفرة البرمجية.
في هذه الحالة هناك رابط مباشر بين خاصيات الوحدة والأسماء العامة والمعرّفة في الوحدة، وهو أنّها تشترك مع بعضها البعض بمجال أسماء واحد.
تنشأ مجالات الأسماء في أوقات مختلفة وتمتلك أعمارًا مختلفة أيضًا. فمجال الأسماء الذي يضمّ الأسماء الداخلية ينشأ عند بدء تشغيل مفسّر بايثون ولا يُحذف على الإطلاق. أما مجال الأسماء العام الخاص بوحدة معينة فينشأ عند تعريف تلك الوحدة ضمن الشيفرة، وعادة ما يبقى مجال الأسماء هذا إلى حين إغلاق مفسّر بايثون.
تكون الشيفرات البرمجية المنفّذة بواسطة الاستدعاء ذي المستوى العالي (top-level invocation) في مفسّر بايثون، سواء أكان مصدر هذه الشيفرات ملف مستقلًّا أو ضمن المفسّر نفسه، جزءًا من وحدة تدعى __main__
؛ لذا تمتلك هذه الشيفرات مجال أسماء عام، وكذلك الأمر بالنسبة للأسماء الداخلية، إذ أنّها جزء من وحدة خاصة تحمل الاسم builtins
.
ينشأ مجال الأسماء المحلي الخاص بدالة معيّنة عند استدعاء تلك الدالة، ويحذف عندما تعيد الدالة قيمة معيّنة أو تطلق استثناء لا تجري معالجته داخل الدالة.
تمتلك الاستدعاءات التعاودية (recursive invocations) مجال أسماء خاص بكل واحد منها.
النطاق scope
النطاق هو جزء من شيفرة بايثون يمكن فيه الوصول إلى مجال الأسماء بصورة مباشرة، والمقصود بذلك هو أنّ الإشارة غير المؤهّلة لاسم معيّن تدفع اللغة إلى البحث عن ذلك الاسم في مجال الأسماء.
وبالرغم من أن النطاقات تحدّد بطريقة سكونية، إلا إنّها تستخدم بطريقة ديناميكية. ففي أي لحظة من لحظات تنفيذ الشيفرة، هناك ما لا يقل عن ثلاثة مجالات متداخلة يمكن الوصول إلى مجالات الأسماء فيها بصورة مباشرة:
- النطاق الداخلي، والذي يجري فيه البحث أوّلًا، ويضمّ الأسماء المحلية.
- النطاقات الخاصّة بأي دالة محيطة، والتي يجري البحث فيها بدءًا من أقرب نطاق محيط، تضمّ أسماء غير محلّية ولكن غير عامّة أيضًا.
- يضمّ النطاق ما قبل الأخير الأسماء العامّة للوحدة الحالية.
- النطاق الخارجي (يجري البحث فيه آخرًا) وهو مجال الأسماء الذي يضمّ الأسماء الداخلية
إن كان الاسم المصرّح عنه عامًّا، فإنّ جميع الإشارات وعمليات الإسناد تذهب مباشرة إلى النطاق الأوسط الذي يضمّ الأسماء العامّة في الوحدة.
يمكن استخدام العبارة nonlocal
لإعادة ربط المتغيّرات الموجودة خارج النطاق الداخلي، وفي حال عدم استخدام هذه العبارة فإنّ المتغيرات ستكون للقراءة فقط (read-only). وتؤدّي أي محاولة للكتابة على هذه المتغيرات إلى إنشاء متغيّر محلي جديد في النطاق الداخلي دون المساس بالمتغيّر الخارجي الذي يحمل الاسم نفسه.
في العادة يشير النطاق المحلي إلى الأسماء المحلية للدالة الحالية، أما خارج الدوال فيشير النطاق المحلي إلى نفس مجال الأسماء الذي يشير إليه النطاق العام، وهو مجال الأسماء الخاص بالوحدة، ويؤدي تعريف أصناف جديدة إلى إضافة مجال أسماء جديد إلى النطاق المحلي.
إنّه لمن الضروري إدراك أنّ تحديد النطاقات يكون نصّيًا، بمعنى أنّ النطاق العام الخاصّ بدالة معيّنة ومعرّفة في وحدة معينة هو مجال الأسماء الخاص بتلك الوحدة بغض النظر عن مكان استدعاء الدالة أو الاختصار المستخدم لذلك.
من جهة أخرى، يجري البحث عن الأسماء بصورة ديناميكية في وقت التشغيل، ولكن اللغة تتّجه بصورة تدريجية إلى تمييز الأسماء سكونيًا، أي في وقت التصريف (complie)؛ لذا لا تعتمد على عملية تمييز الأسماء الديناميكية. (في الواقع، المتغيرات المحلية تحدّد بصورة سكونية).
تختلف بايثون عن غيرها من اللغات في أنّه عند غياب عبارة عامة فإنّ عمليات الإسناد إلى الأسماء تذهب إلى النطاق الداخلي، ويجب الانتباه إلى أن عمليات الإسناد لا تنسخ البيانات، وإنّما تربط الأسماء بالكائنات، وهذا الأمر ينطبق أيضًا على عملية الحذف، فعبارة del x
تقطع الرابط بين x
وبين مجال الأسماء المشار إليه عن طريق النطاق المحلي.
في الواقع تستخدم جميع العمليات التي تقدّم أسماء جديدة النطاقَ المحلي، وعلى وجه الخصوص تعمل عبارات import
وتعاريف الدوال على ربط الوحدات أو اسم الدالة في النطاق المحلي.
يمكن استخدام عبارة global
للإشارة إلى أن المتغيّر موجود في النطاق العام وأن إعادة الربط يجب أن تتم في ذاك النطاق. كذلك يمكن استخدام العبارة nonlocal
للإشارة إلى أن المتغير موجود في نطاق محيط وأنّ إعادة تعريفه يجب أن تكون في ذاك النطاق.
أمثلة على النطاقات ومجالات الأسماء
يوضح المثال التالي كيفية الإشارة إلى نطاقات ومجالات أسماء مختلفة، وكيف تؤثر عبارتا global
و nonlocal
على عملية ربط المتغيرات:
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
لاحظ كيف أنّ الإسناد المحلي (وهو الافتراضي) لم يغيّر ربط الدالة scope_test()
بالمتغيّر spam
. أما عملية الإسناد المسبوقة بعبارة nonlocal
فقد غيّرت ربط الدالة بالمتغير spam
، أما عبارة global
فقد غيّرت الربط على مستوى الوحدة ككل.
لاحظ كذلك أنّه لم يكن هناك أي ربط مسبق مع المتغير spam
قبل عملية الإسناد العامّة.
مصادر
- صفحة Classes في توثيق بايثون الرسمي.