آموزش پایتون-کلاس ها و Namespaces در Python
سلام دوستان...
در این قسمت از آموزش پایتون با مفهوم کلاس ها آشنا میشوید:
آموزش کلاس ها در برنامه نویسی پایتون
کلاس ها ابزاری برای بسته بندی داده و عملکرد با یکدیگر را ارائه می کنند. ساخت یک کلاس جدید، یک نوع جدید از شی می سازد، که امکان ساخت نمونه های جدیدی از آن نوع را فراهم می کند. هر نمونه کلاس می تواند ویژگی هایی متصل به خود برای نگه داری حالت خود داشته باشد. همچنین نمونه کلاس ها می توانند متدهایی (تعریف شده توسط کلاس خود) برای تغییر حالت خود داشته باشند.
در مقایسه با سایر زبان های برنامه نویسی، مکانیزم کلاس در پایتون با حداقل تعداد نحو و مفاهیم (syntax and semantics) جدید، کلاس اضافه می کند. این مکانیزم، ترکیبی از مکانیزم کلاس موجود در C++ و Modula-3 است.
کلاس های پایتون تمامی ویژگی های استاندارد برنامه نویسی شی گرا را ارائه می کنند : مکانیزم وراثت در کلاس، چندین کلاس پایه را مجاز می شمارد. یک کلاس مشتق شده می تواند هر متدی از کلاس(ها) پایه خود را تغییر دهد (override) ، و یک متد می تواند متدی از یک کلاس پایه با نام مشابه را فراخوانی کند. اشیا می توانند دربردارنده حجم و انواع داده دلخواه باشند. همانطور که برای ماژول ها صادق است، کلاس ها در طبیعت پویای پایتون نیز سهیم هستند. آنها در زمان اجرا ساخته می شوند، و پس از ساخت می توانند تغییر کنند.
در اصطلاحات C++ ، معمولا اعضای کلاس (از جمله اعضای داده) عمومی (public) هستند
و تمامی توابع عضو مجازی (virtual) هستند. همانند Modula-3 ، هیچ خلاصه نویسی برای ارجاع به اعضای اشیا، از متد آنها وجود ندارد. تابع متد، توسط آرگومان اول که صریحا شی را نمایش می دهد، که به طور ضمنی توسط فراخوانی فراهم شده است، اعلان می شود.
همانند Smalltalk ، کلاس ها خود شی هستند. این مسئله مفاهیم واردات (importing) و تغییر نام را ارائه می کند. بر خلاف C++ و Modula-3 ، انواع داخلی (built-in) می تواند به عنوان کلاس های پایه برای توسعه توسط کاربر استفاده شود. همچنین، همانند C++، اکثر عملگرهای داخلی با نحو خاص (عملگرهای ریاضی، زیرنویس ها و غیره)می توانند برای نمونه کلاس دوباره تعریف شوند.
(به دلیل فقدان اصطلاحاتی که به طور جهانی درباره کلاس ها پذیرفته شده باشد، من گاه به گاه از واژه های C++ و Modula-3 استفاده می کنم. من از واژه های Modula-3 استفاده خواهم کرد، زیرا مفاهیم شی گرایی آن نسبت به C++ به پایتون نزدیک تر است، اما انتظار دارم تعداد کمی از خواننده ها درباره آن شنیده باشند.)
سخنی درباره نام ها و اشیا در Python
اشیا دارای فردیت هستند، و چندین نام (در چندین حوزه) می توانند به همان شی محدود شوند. این امر با عنوان نام مستعار (aliasing) در سایر زبان ها شناخته شده است.
معمولا در نگاه اول به پایتون، از این موضوع استقبال نمی شود، و می توان هنگام کار با انواع پایه تغییر ناپذیر(اعداد، رشته ها و چندتایی ها (tuples)) آن را به صورت ایمن نادیده گرفت. هر چند، نام مستعار یک اثر شگفت انگیز محتمل روی مفاهیم کد پایتونی دارد که این کدها شامل اشیای تغییر پذیر مانند لیست ها، دیکشنری ها و بیشتر انواع دیگر هستند.
از آنجایی که نام مستعار از بعضی جهات مانند اشاره گر رفتار می کند، معمولا از این قابلیت به نفع برنامه استفاده می شود. برای مثال، پاس دادن یک شی ارزان است، زیرا تنها یک اشاره گر توسط پیاده سازی انتقال می یابد، و اگر یک تابع شی ای که به عنوان یک آرگومان پاس داده شده است را تغییر دهد، فراخواننده (caller) تغییرات را خواهد دید—این امر الزام پاس دادن مکانیزم ها توسط دو آرگومان متفاوت (مانند Pascal) را از بین می برد.
آموزش پایتون : حوزه ها و فضاهای نام در برنامه نویسی پایتون
قبل از معرفی کلاس ها، ابتدا باید اطلاعاتی درباره قوانین حوزه های (scope) پایتون را در اختیارتان قرار دهم. تعاریف کلاس با ترفندهایی با فضاهای نام (namespaces) بازی می کنند، و شما برای فهمیدن اینکه چه اتفاقی در حال رخ دادن است، باید بدانید حوزه ها و فضاهای نام چگونه کار می کنند. اتفاقا، داشتن دانش درباره این موضوع برای هر برنامه نویس حرفه ای پایتون مفید است. بیایید با تعدادی از تعاریف شروع کنیم.
آموزش Namespaces در Python
فضای نام یک نگاشت از نام ها به اشیا است. اکثر فضاهای نام در حال حاضر به عنوان دیکشنری های پایتون پیاده سازی شده اند، اما به طور معمول به هیچ وجه قابل توجه نیستند (به جز برای کارایی)، و ممکن است در آینده تغییر کنند. مثال هایی از فضای نام عبارتند از: مجموعه ای از نام های داخلی(built-in) (شامل توابعی مانند abs()، و نام استثناهای داخلی)، نام های سراسری در یک ماژول، و نام های محلی در یک فراخوانی تابع. به این معنا که مجموعه ای از ویژگی های یک شی، یک فضای نام را نیز تشکیل می دهند.
نکته مهمی که باید درباره فضاهای نام بدانید این است که مطلقا هیچ ارتباطی بین نام ها در فضاهای نام مختلف وجود ندارد. برای مثال، ممکن است دو ماژول مختلف، هر دو یک تابع به نام maximize را بدون ابهام تعریف کنند—کاربران ماژول ها باید آن را با نام ماژول، پیشوند سازی کنند.
ضمنا، من از کلمه ‘ویژگی’ برای هر نامی که پس از یک نقطه بیاید استفاده می کنم—برای مثال، در عبارت z.real ، real یک ویژگی شی z است. تاکید می کنم، ارجاع به نام ها در ماژول ها، ارجاع ویژگی است. در این مورد، یک نگاشت مستقیم بین ویژگی های ماژول و نام های سراسری تعریف شده در ماژول رخ می دهد. آنها فضای نام یکسانی را به اشتراک می گذارند.
آموزش Attributes در Python
ویژگی ها می توانند فقط-خواندنی یا قابل نوشتن باشند. در حالت دوم، تخصیص به ویژگی ها امکان پذیر است. ویژگی های ماژول قابل نوشتن هستند: می توانید بنویسید modname.the_answer = 42 . همچنین ممکن است ویژگی های قابل نوشتن توسط عبارت del پاک شوند. برای مثال، del modname.the_answer ویژگی the_answer را از شی ای به نام modname حذف می کند.
فضاهای نام در زمان های مختلف ساخته می شوند و طول عمر متفاوتی دارند. یک فضای نام شامل نام های داخلی، در زمان آغاز به کار مفسر پایتون ساخته می شود، و هرگز پاک نمی شود. فضای نام سراسری برای یک ماژول، در زمان خوانده شدن تعریف ماژول ساخته می شود.
معمولا، فضای نام ماژول نیز تا زمان اتمام کار مفسر باقی می ماند. عبارات اجرا شده توسط فراخوانی سطح بالای مفسر، که از یک فایل script خوانده شده یا به صورت تعاملی وارد شده است، به عنوان بخشی از یک ماژول به نام __main__ در نظر گرفته می شود. بنابراین آنها فضای نام سراسری خود را دارند. ( در واقع نام های داخلی نیز درون یک ماژول می مانند، این builtins نام دارد.)
فضای نام محلی برای یک تابع، در زمان فراخوانی تابع ساخته می شود، و زمانی که تابع مقداری را باز گرداند یا استثنایی را اعلام کند که درون تابع اداره نشده باشد، پاک می شود. ( در واقع، فراموش کردن روش بهتری برای توصیف چیزی است که واقعا رخ می دهد.) البته، فراخوانی های بازگشتی فضای نام محلی خود را دارند.
آموزش scope در Python
حوزه (scope) یک ناحیه متنی از یک برنامه پایتون است، جایی که فضای نام مستقیما در دسترس است. در اینجا “دسترسی مستقیم” به این معنی است که یک ارجاع فاقد صلاحیت به یک نام، برای پیدا کردن نام در فضای نام اقدام می کند.
اگر چه حوزه ها به صورت ایستا تعیین می شوند، به صورت پویا استفاده می شوند. در هر زمانی حین اجرا، حداقل سه حوزه تو در تو وجود دارد که فضاهای نام آنها مستقیما در دسترس هستند.
- داخلی ترین حوزه، که ابتدا جستجو می شود، در بر دارنده نام های محلی است.
- حوزه های توابع محصور، که با جستجو از نزدیک ترین حوزه محصور شروع می کند، در بر دارنده نام های غیر محلی و همچنین غیر سراسری است.
- حوزه یکی مانده به آخر در بر دارنده نام های سراسری ماژول فعلی است.
- خارجی ترین حوزه (که در انتها جستجو می شود) فضای نامی است که در بر دارنده نام های داخلی است.
اگر یک نام به عنوان سراسری اعلام شود، تمامی ارجاع ها و تخصیص ها مستقیما به حوزه میانی می رود، که در بر دارنده نام های سراسری ماژول است. برای به هم پیوستن مجدد متغیرهایی که خارج از داخلی ترین حوزه پیدا شده اند، می توان از عبارت nonlocal استفاده کرد. اگر غیر محلی اعلام نشده باشد، آن متغیر ها فقط-خواندنی هستند ( اقدام برای نوشتن در چنین متغیری، به سادگی یک متغیر محلی جدید درون داخلی ترین حوزه می سازد، و متغیر خارجی با نام عینا مشابه را بدون تغییر رها می کند).
معمولا حوزه محلی، به نام های محلی (متنی) مربوط به تابع جاری ارجاع می دهد. توابع خارجی، حوزه محلی به فضای نام مشابه حوزه سراسری ارجاع می دهد که فضای نام ماژول است. تعاریف کلاس، یک فضای نام دیگری را در حوزه محلی قرار می دهد.
مهم است بدانیم که حوزه ها به صورت متنی مشخص می شوند: حوزه سراسری یک تابع که درون یک ماژول تعریف شده است، فضای نام آن ماژول است، فارغ از این که تابع از کجا یا توسط کدام ناشناسی فراخوانده شده باشد. از طرف دیگر، جستجوی واقعی برای نام ها به صورت پویا در زمان اجرا انجام می شود.
اگر چه، تعریف زبان به سمت وضوح نام به صورت ایستا در زمان کامپایل، در حال تغییر است. بنابراین به وضوح نام به صورت پویا تکیه نکنید! (در حقیقت متغیر های محلی در حال حاضر به صورت ایستا تعیین می شود.)
یک تغییر خاص در پایتون این است که -- اگر هیچ عبارت سراسری یا غیر محلی نباشد—تخصیص به نام ها همیشه به داخلی ترین حوزه می رود. تخصیص ها داده را کپی نمی کنند—آنها فقط نام ها را به اشیا اتصال می دهند. درباره پاک کردن نیز همینطور است. عبارت del x ، اتصال x و فضای نام ارجاع یافته توسط حوزه محلی را حذف می کند. در حقیقت تمام عملیاتی که نام های جدیدی را معرفی می کنند از حوزه محلی استفاده می کنند. به خصوص، عبارات import و تعاریف تابع، نام ماژول یا تابع را در حوزه محلی متصل می کند.
از عبارت سراسری می توان برای بیان متغیر های خاصی که در حوزه سراسری وجود دارند و باید به آن بازگردانده شوند استفاده کرد. عبارت غیر محلی بیان می کند که متغیر های خاص درون حوزه محصور وجود دارند و باید به آن بازگردانده شوند.
مثال حوزه ها و فضاهای نام در Python
این مثال چگونگی ارجاع به حوزه ها و فضاهای نام مختلف و نیز چگونگی تاثیرگذاری سراسری و غیر محلی بودن روی اتصال(binding) متغیر ها را نمایش می دهد.
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
توجه داشته باشید که چگونه تخصیص محلی (که پیش فرض است) اتصال(binding) spam مربوط به scope_test را تغییر نداد. تخصیص غیر محلی، اتصال spam مربوط به scope_test را تغییر داد، و تخصیص سراسری اتصال سطح ماژول را تغییر داد. همچنین می توانید ببینید که قبل از تخصیص سراسری، هیچ اتصالی از قبل برای spam وجود نداشته است.
آموزش پایتون ادامه دارد
مطلبی دیگر از این انتشارات
الگویِ طراحی Command (جاوا و کاتلین)
مطلبی دیگر از این انتشارات
برنامه نویسی چیست؟ برنامه نویس کیه؟
مطلبی دیگر از این انتشارات
جلسه سوم آموزش پایتون: نصب پایتون