قبل از معرفی کلاسها، اول باید چیزی درباره قوانین دامنه پایتون به شما بگویم. تعریفهای کلاس ترفندهای خوبی با فضاهای نام ایجاد میکنند و باید بدانید دامنهها و فضاهای نام چگونه کار میکنند تا کاملاً درک کنید چه اتفاقی میافتد. ضمناً، دانش درباره این موضوع برای هر برنامهنویس پایتون پیشرفتهای مفید است.
بیایید با برخی تعریفها شروع کنیم.
فضای نام (namespace) نگاشتی از نامها به اشیاء است. بیشتر فضاهای نام در حال حاضر به صورت دیکشنریهای پایتون پیادهسازی شدهاند، اما این معمولاً به هیچ وجه قابل توجه نیست (به جز از نظر کارایی) و ممکن است در آینده تغییر کند. نمونههایی از فضاهای نام: مجموعه نامهای داخلی (شامل توابعی مانند abs() و نامهای استثناء داخلی)؛ نامهای سراسری در یک ماژول؛ و نامهای محلی در فراخوانی یک تابع. در حسی، مجموعه ویژگیهای یک شیء نیز فضای نام تشکیل میدهد. چیز مهمی که باید درباره فضاهای نام بدانید این است که هیچ رابطهای بین نامها در فضاهای نام مختلف وجود ندارد؛ به عنوان مثال، دو ماژول مختلف هر دو میتوانند تابعی به نام maximize تعریف کنند بدون ابهام — کاربران ماژولها باید آن را با نام ماژول پیشوند کنند.
ضمناً، من کلمه ویژگی (attribute) را برای هر نامی که بعد از یک نقطه میآید استفاده میکنم — مثلاً، در عبارت z.real، real یک ویژگی شیء z است. به طور دقیق، مراجع به نامها در ماژولها مراجع ویژگی هستند: در عبارت modname.funcname، modname یک شیء ماژول است و funcname ویژگی آن است. در اینجا به طور اتفاقی نگاشت سادهای بین ویژگیهای ماژول و نامهای سراسری تعریف شده در ماژول وجود دارد: آنها فضای نام یکسانی دارند!
ویژگیها میتوانند فقط خواندنی یا نوشتنی باشند. در حالت دوم، اختصاص به ویژگیها ممکن است. ویژگیهای ماژول نوشتنی هستند: میتوانید modname.the_answer = 42 بنویسید. ویژگیهای نوشتنی همچنین میتوانند با دستور del حذف شوند. به عنوان مثال، del modname.the_answer ویژگی the_answer را از شیء نامبرده شده توسط modname حذف میکند.
فضاهای نام در لحظات مختلف ایجاد شده و طول عمرهای مختلفی دارند. فضای نام حاوی نامهای داخلی زمانی ایجاد میشود که مفسر پایتون راهاندازی شود و هرگز حذف نمیشود. فضای نام سراسری یک ماژول زمانی ایجاد میشود که تعریف ماژول خوانده شود؛ معمولاً فضاهای نام ماژول نیز تا خروج مفسر باقی میمانند. عبارات اجرا شده توسط فراخوانی سطح بالای مفسر، خوانده شده از یک فایل اسکریپت یا به صورت تعاملی، بخشی از ماژولی به نام __main__ در نظر گرفته میشوند و بنابراین فضای نام سراسری خودشان را دارند. (نامهای داخلی در واقع در یک ماژول نیز زندگی میکنند؛ به آن builtins گفته میشود.)
فضای نام محلی یک تابع زمانی ایجاد میشود که تابع فراخوانی شود، و زمانی حذف میشود که تابع برگرداند یا استثنایی ایجاد کند که در داخل تابع مدیریت نشده باشد. (در واقع، فراموشی روش بهتری برای توصیف آنچه واقعاً اتفاق میافتد است.) البته، فراخوانیهای بازگشتی هر کدام فضای نام محلی خودشان را دارند.
دامنه (scope) ناحیه متنی یک برنامه پایتون است که در آن یک فضای نام مستقیماً در دسترس است. «مستقیماً در دسترس» اینجا به این معناست که یک مرجع بدون صلاحیت به یک نام تلاش میکند نام را در فضای نام پیدا کند.
اگرچه دامنهها به صورت استاتیک تعیین میشوند، به صورت دینامیک استفاده میشوند. در هر زمانی در حین اجرا، ۳ یا ۴ دامنه تودرتو وجود دارد که فضاهای نام آنها مستقیماً در دسترس هستند:
اگر نامی به عنوان سراسری اعلان شود، تمام مراجعات و اختصاصها مستقیماً به دومین دامنه از آخر که حاوی نامهای سراسری ماژول است میروند. برای باز متصل کردن متغیرهایی که خارج از داخلیترین دامنه یافت میشوند، دستور nonlocal میتواند استفاده شود؛ اگر به عنوان nonlocal اعلان نشده باشند، این متغیرها فقط خواندنی هستند (تلاش برای نوشتن در چنین متغیری فقط یک متغیر محلی جدید در داخلیترین دامنه ایجاد میکند).
معمولاً، دامنه محلی به نامهای محلی تابع (متنی) جاری ارجاع میدهد. خارج از توابع، دامنه محلی به همان فضای نام دامنه سراسری ارجاع میدهد: فضای نام ماژول. تعریفهای کلاس فضای نام دیگری در دامنه محلی قرار میدهند.
مهم است درک کنید که دامنهها به صورت متنی تعیین میشوند: دامنه سراسری تابعی که در یک ماژول تعریف شده، فضای نام آن ماژول است، صرف نظر از اینکه از کجا یا با چه نام مستعاری تابع فراخوانی شود. از طرف دیگر، جستجوی واقعی نامها به صورت دینامیک در زمان اجرا انجام میشود — با این حال، تعریف زبان به سمت حل نامهای استاتیک در حال تکامل است، پس به حل نامهای دینامیک اعتماد نکنید!
یک ویژگی خاص پایتون این است که — اگر هیچ دستور global یا nonlocal در کار نباشد — اختصاصها به نامها همیشه به داخلیترین دامنه میروند. اختصاصها دادهها را کپی نمیکنند — فقط نامها را به اشیاء متصل میکنند. همین درباره حذفها نیز صدق میکند: دستور 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
توجه کنید چگونه اختصاص محلی (که پیشفرض است) اتصال spam توسط scope_test را تغییر نداد. اختصاص nonlocal اتصال spam توسط scope_test را تغییر داد و اختصاص global اتصال سطح ماژول را تغییر داد.
همچنین میتوانید ببینید که قبل از اختصاص global اتصال قبلی برای spam وجود نداشت.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://docs.python.org/3/tutorial