امروز میخوام محدوده و فضای نام یا scope و Namespaces در پایتون رو به صورت خیلی ساده و روان برای شما توضیح بدم.
تویی که تازه اومدی امیدوارم که به همین سادگی کل موضوع بگیری ولی تویی که هرجا گشتی و هرچی خوندی ولی انگار میفهمی و فهمیدی ولی باز یه چیزی کمه و انگار کامل مفهوم نگرفتی و یه جای ذهنت میگه دوست من ابهام داری، امیدوارم گره از مشکلت باز کنم.
خب بیاییم بریم سر اصل مطلب
خیلی ساده بگیم scope یعنی متغیری یک محدوده ای باش چه مقداری داره. کد زیر را نگاه کنید.
def print_number(): num=10 print(num) print_number()
اجرا گرفتیم جواب شد 10 درسته؟
خب الان میگم. ما سه نوع فضای نام داریم محلی(local) غیر محلی (nonlocal) و سراسری (global)
الان اینی که تو کد بالا هستن متغیر num یک متغیر محلی فقط تو محدوده تابع مقدار داره چرا چون فضای نام محلی وقتی تابع فراخوانی میشه ایجاد میشه و وقتی تموم میشه فضای نام آن حذف میشه
حالا اگه کد زیر را اجرا کنیم خطا میده چرا چون print(num) دومی چون داخل محدوده تابع نیست و متغیnum درون تابع بعد print ی که داخل تابع بود، حذف شد.
def print_number(): num=10 print(num) print_number() print(num)
#NameError: name 'num' is not defined
حالا اگه این کد زیر را اجرا کنیم و این تغییر کوچیک بدیم دیگه print دومی جواب میده بهمون چرا چون num=20 در کل ماژول خارج تابع این مقدار داره به این میگن متغیر global
num=20 def print_number(): num=10 print(num) print_number() print(num)
#10
#20
حالا سوال میتونه پیش بیاد اگه بخواییم متغیر global که num خط اول هستش را داخل تابع تغییر بدیم چی کار کنیم؟
اینجاست که کلمه کلیدی global به کار میاد کد زیر را ببینین num خارج تابع یعنی داخل ماژول تغییر میده
num=20 def print_number(): num=10 print(num) def global_def(): global num num=50 # این اینجا صدا زدم تا تابع اجرا بشه اگه نزنیم که دستورات داخلش اجرا نمیشن global_def() print_number() print(num)
#10
#50
هنوز یکی مونده متغیر nonlocal
حالا یک مثال از خود سایت پایتون میارم البته یه کوچولو تغییر میدم یعنی یه پرینتی اضافه میکنم تا جا بیافته حالا بریم تا ببینیم و تفسیرش کنیم اینو اجرا کنین و ببینین و کامنت هاش بخونین که خیلی مهم.
این کد خیلی خوبه ولی اگه سخت برای شما برین روی کد های بعدی
def scope_test(): def do_local(): spam = "local spam" print("in 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)
#in local: local spam
#After local assignment: test spam
#After nonlocal assignment: nonlocal spam
#After global assignment: nonlocal spam
#In global scope: global spam
درکل موضوع فهمیدی که خوبه اگه سخت بود و نفهمیدی این چند تیکه کد اجرا کن و تغییرات دنبال کن
def A(): a=10 def B(): nonlocal a a=20 #چون هیچکدوم از توابع داخلی صدا زده نشدن از مقدار لوکال آ که 10 بود میخونه print(a) A()
10
یه کوچولو تغییر میدیم
def A(): a=10 def B(): nonlocal a a=20 B() print(a) A()
20
مقدار 20 چاپ میشه چرا؟ چون تابع B صدا زدیم و مقدار a خارج B و همچنین داخل تابع A از 10 شد 20
حالا یه تغییر دیگه
def A(): a=10 def B(): nonlocal a a=20 def C(): nonlocal a a=30 C() B() print(a) A()
30
خروجی شد 30 چرا به همون دلیل بالایی ولی بعد صدا زده شدن B , تابع C هم صدا زده شد و مقدار اون اخرین مقدار برای a
حال متغیر سراسری ببینیم یا همون global
a=50 def A(): a=10 def B(): nonlocal a a=20 def C(): nonlocal a a=30 C() B() print(a) A() print(a)
30
50
جواب شد 30 بخاطر توضیحات قبل ولی پرینت خط اخر 50 برگردوند چرا چون نه داخل تابع از کلمه کلیدی گلوبال برای مقدار دهی به a استفاده کردیم و نه تا برسیم به پرینت اخری مقدار a را خارج تابع تغییر دادیم. این دو حالت باعث تغییر a گلوبال میشدن
حال متغیر غیر محلی را به سراسری در داخل تابع C تغییر میدیم
a=50 def A(): a=10 def B(): nonlocal a a=20 def C(): global a # see there a=30 C() B() print(a) A() print(a)
20
30
خروجی اول شد 20 چرا بخاطر تابع B و خروجی دوم شد 30 چرا چون داخل تابع C مقدار متغیر سراسری که داخل ماژول هستش و خارج تابع وجود داره تغییر میکنه
امیدوارم مطلب به شکل مناسب رسانده باشم