توضیح scope , Namespaces در پایتون

امروز میخوام محدوده و فضای نام یا scope و Namespaces در پایتون رو به صورت خیلی ساده و روان برای شما توضیح بدم.تویی که تازه اومدی امیدوارم که به همین سادگی کل موضوع بگیری ولی تویی که هرجا گشتی و هرچی خوندی ولی انگار میفهمی و فهمیدی ولی باز یه چیزی کمه و انگار کامل مفهوم نگرفتی و یه جای ذهنت میگه دوست من ابهام داری، امیدوارم گره از مشکلت باز کنم.خب بیاییم بریم سر اصل مطلب خیلی ساده بگیم scope یعنی متغیری یک محدوده ای باش چه مقداری داره. کد زیر را نگاه کنید.def print_number(): num=10 print(num) print_number()#10اجرا گرفتیم جواب شد 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 = &quotlocal spam&quot print(&quotin local:&quot,spam) def do_nonlocal(): nonlocal spam spam = &quotnonlocal spam&quot def do_global(): global spam spam = &quotglobal spam&quot spam = &quottest spam&quot # ببینین اینجا این تابع صدا زده شد اسپم مقدار نداره ولی داخل این تابع فقط مقدار لوکال اسپم میگیره و چاپ میکنه do_local() # ولی اینجا نه اینطور نیست اون داخل تابع دو لوکال بود اینجا دیگه مقداری که در هم راستاش گرفته رو داره یعنی تست اسپم print(&quotAfter local assignment:&quot, spam) #اینجا غیر محلی صدا میزنیم do_nonlocal() # موقع چاپ چه بلایی سر متغیر اسپم میاد؟ ببینین نال لوکال میگه که من هم مقدار اسپم داخل تابع دوـلوکال تغییر میدم هم خارج دوـناللوکال و خارج کل توابع که گلوبال رو نمیتونم print(&quotAfter nonlocal assignment:&quot, spam) # اینجا گلوبال اجرا میشه ولی چیکار میکنه اسپم خارج کل توابع یعنی داخل ماژول پایتون تغییر میده چه از قبل ساختیم چه نساختیم do_global() # حالا میخواد چاپ کنه چیو چاپ میکنه ؟ نان لوکال چرا چون نال لوکال اومده هم داخل خودش و هم داخل تابع بیرونی مقدار اسپم تغییر داده print(&quotAfter global assignment:&quot, spam) scope_test() #اینجا هم متغیر اسپم خارج کل تابع میفهمه ولی چی چاپ میکنه سراسری یا گلوبال چرا چون داخل تابع با کلمه کلیدی گلوبال این اسپم ی که خارج از تابع و کل ماژول اعتبار داره را تغییر دادیم و مقدار دادیم بهتر بگم print(&quotIn global scope:&quot, 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حال متغیر سراسری ببینیم یا همون globala=50 def A(): a=10 def B(): nonlocal a a=20 def C(): nonlocal a a=30 C() B() print(a) A() print(a)3050جواب شد 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)2030خروجی اول شد 20 چرا بخاطر تابع B و خروجی دوم شد 30 چرا چون داخل تابع C مقدار متغیر سراسری که داخل ماژول هستش و خارج تابع وجود داره تغییر میکنهامیدوارم مطلب به شکل مناسب رسانده باشم