مدیریت محدوده یا Scope متغیرها یکی از مفاهیم بنیادی در پایتون است. اینکه یک متغیر در کجا تعریف شده و در چه بخشهایی از کد قابل دسترسی یا تغییر است، رفتار برنامه را تعیین میکند. در این مقاله به بررسی دقیق فضاهای نام (Namespaces) و کلمات کلیدی global و nonlocal میپردازیم.

سطح مقدماتی (Beginner Level)
در سطح مقدماتی، با دو مفهوم اصلی آشنا میشویم: Global Scope (محدوده سراسری) و Local Scope (محدوده محلی). همچنین یاد میگیریم چگونه متغیرهایی که بیرون از تابع تعریف شدهاند را داخل تابع تغییر دهیم.
۱. مفهوم قلمرو (Scope) و متغیرهای محلی و سراسری
- Global Variables: متغیرهایی که در بدنه اصلی فایل (خارج از تمام توابع) تعریف میشوند. این متغیرها در تمام طول برنامه قابل خواندن هستند.
- Local Variables: متغیرهایی که داخل یک تابع تعریف میشوند و فقط درون همان تابع زنده هستند.
مثال ۱: خواندن متغیر سراسری در داخل تابع
در این مثال، تابع print_message متغیر message را که سراسری است میخواند. این کار بدون هیچ کلمه کلیدی خاصی امکانپذیر است.
مثال ۲: تفاوت متغیر محلی و سراسری همنام
اگر متغیری همنام با متغیر سراسری در داخل تابع تعریف کنید، پایتون یک متغیر محلی جدید میسازد و کاری به متغیر بیرونی ندارد.
۲. کلمه کلیدی global
اگر بخواهیم مقدار یک متغیر سراسری را از داخل تابع تغییر دهیم، پایتون به طور پیشفرض اجازه این کار را نمیدهد (آن را به عنوان تعریف متغیر جدید محلی میبیند). برای حل این مشکل، باید صریحاً به پایتون بگوییم که منظورمان متغیر سراسری است.
مثال ۱: استفاده از global برای تغییر مقدار
در اینجا با استفاده از global count، به تابع دسترسی نوشتن روی متغیر بیرونی را میدهیم.
مثال ۲: خطای رایج (UnboundLocalError)
اگر بدون استفاده از global سعی کنید متغیری را که بیرون تعریف شده تغییر دهید (مثلاً x += 1)، پایتون خطا میدهد.
# Example 4: This snippet causes an error because 'x' is treated as local but not initialized
x = 10
def bad_increment():
# پایتون فکر میکند x محلی است، اما هنوز مقداردهی نشده
x = x + 1 # Raises UnboundLocalError
return x
سطح پیشرفته (Professional Level)
در سطح حرفهای، وارد بحث توابع تودرتو (Nested Functions) و مفهوم Enclosing Scope میشویم. اینجا جایی است که کلمه کلیدی nonlocal اهمیت پیدا میکند. همچنین قانون LEGB را بررسی میکنیم.
۱. قانون LEGB در پایتون
پایتون برای پیدا کردن مقدار یک متغیر، به ترتیب زیر جستجو میکند:
- Local: داخل تابع فعلی.
- Enclosing: داخل تابع پدر (در توابع تودرتو).
- Global: سطح ماژول اصلی.
- Built-in: نامهای پیشفرض پایتون (مثل
len,print).
۲. کلمه کلیدی nonlocal
کلمه کلیدی global به بالاترین سطح (سراسری) اشاره دارد، اما nonlocal به نزدیکترین قلمرو بیرونی (Enclosing) اشاره میکند که سراسری نیست. این کلمه کلیدی مختص توابع تودرتو (Nested Functions) است.
مثال ۱: استفاده از nonlocal در توابع تودرتو
در اینجا تابع inner میخواهد متغیر x که متعلق به تابع outer است را تغییر دهد.
مثال ۲: مقایسه رفتار بدون nonlocal
بدون این کلمه کلیدی، تابع داخلی یک متغیر جدید میسازد و متغیر تابع پدر دستنخورده باقی میماند.
۳. تفاوت دقیق global و nonlocal
global: مستقیماً به فضای نام ماژول میپرد (Global Scope).nonlocal: یک پله به عقب میرود (به توابع دربرگیرنده) اما به Global نمیرسد.
مثال: ترکیب هر دو در یک ساختار پیچیده
این مثال نشان میدهد چگونه global از چندین لایه تابع عبور میکند، اما nonlocal فقط به لایه قبلی ارجاع میدهد.
۴. نکات فنی و بهترین روشها (Best Practices)
- پرهیز از Global: استفاده زیاد از متغیرهای سراسری کد را غیرقابل پیشبینی و دیباگ را سخت میکند. بهتر است دادهها را از طریق آرگومانها پاس دهید.
- اشیاء تغییرپذیر (Mutable Objects): اگر متغیر شما یک لیست یا دیکشنری است، برای تغییر محتویات آن (مثلاً
append) نیازی بهglobalیاnonlocalندارید، زیرا ارجاع (Reference) متغیر تغییر نمیکند.
مثال فنی: تغییر لیست بدون کلمه کلیدی
در اینجا نیازی به global نیست چون ما my_list را دوباره مقداردهی (=) نمیکنیم، بلکه متد داخلی آن را صدا میزنیم.
مثال فنی: کلوژر (Closure) و حفظ حالت
استفاده از nonlocal اساس ساخت Closureهاست که به توابع اجازه میدهد "حالت" (State) خود را بین فراخوانیها حفظ کنند.