کتاب عصر پایتون/فصل ششم: برنامه‌نویسی شیءگرا

ویکی‎کتاب، کتابخانهٔ آزاد
پرش به ناوبری پرش به جستجو
Gnome-go-last.svg Gnome-go-first.svg

کتاب عصر پایتون به کمک علاقه‌مندان ایرانی پایتون جمع‌آوری شده‌است. اين كتاب بر اساس مجوز گنو ارايه می‌گردد [۱]

مفهوم شیءگرایی[ویرایش]

مقدمه[ویرایش]

برای برنامه‌نویسی شیءگرا در هر زبانی ابتدا باید مفهوم اصلی شیءگرایی را درک کرد. شیءگرایی ابزار و یا خصوصیت خاص یک زبان برنامه‌نویسی نیست؛ حتی در زبانی مثل C هم که از امکانات شیءگرایی برخوردار نیست، باز هم امکان برنامه‌نویسی شیءگرا وجود دارد. نمونه‌ای بارز از این گونه برنامه‌ها، کتابخانۀ معروف GTK است که به‌صورت شیءگرا در C پیاده‌سازی شده است. در حقیقت شیءگرایی نوعی طرز تفکر خاص در پیاده‌سازی برنامه‌ها است. به این صورت که برنامه‌نویس با قسمت‌های مختلف برنامه‌اش دقیقاً همانند اشیای عادی در دنیای حقیقی رفتار می‌کند، و سعی می‌کند با کنار هم قرار دادن آن‌ها برنامۀ خود را به سرانجام برساند.

مثال‌هایی از دنیای واقعی[ویرایش]

مثال ۱: نجاری را در نظر بگیرید که برای ساخت یک میز باید از اشیای مختلفی مثل میخ، چکش، اره و... استفاده کند. هر کدام از این ابزارها اشیای جداگانه‌ای هستند که بدون دخالت در کار یکدیگر به ساخت میز مورد نظر نجار کمک می‌کنند. چکش میخ را می‌کوبد بدون این که از ماهیت میخ با خبر باشد... اره چوب را تکه‌تکه می‌کند بدون این که در کار چکش دخالت کند.... در نهایت حاصل کار میزی خواهد بود؛ که نجار با استفاده از این ابزارها پدید آورده است. در حقیقت نجار برای ساخت میز خود از اشیای مختلفی که هر کدام ماهیت و خصوصیات خاص خودشان را دارند کمک گرفت.

مثال ۲: فرض نمایید که ما قصد داریم قطعه‌ای را به‌طور انبوه تولید نماییم. یک روش آن است که ما این قطعات را یک‌به‌یک تراش دهیم ولی این کار ممکن است ماه‌ها و شاید سال‌ها زمان برد. و اگر نتیجه کار را هم بررسی نماییم ملاحظه می‌کنیم که قطعات همگی یک‌شکل و یک‌دست نیستند همچینین هزینۀ تمام شدۀ آن هم بسیار بالا خواهد بود. اما روش بهتری نیز وجود دارد و آن این است که ما یک قالب برای آن قطعه بسازیم و بعد با استفاده از آن قالب قطعات مورد نیاز خود را تولید نماییم. پس اگر ما فقط در ساختن قالب دقت لازم را به خرج دهیم، در پایان کار مشاهده می‌کنیم که قطعات تولید شده همگی یک‌شکل و یک‌دست از آب درآمده‌اند. در برنامه‌نویسی شیءگرا هم در واقع از این روش استفاده می‌شود ما یک قالب (کلاس) می‌سازیم و آن را امتحان می‌کنیم تا از درستی طرز کار آن مطمئن شویم. سپس از آن بارها استفاده می‌نماییم.

مزایای شیءگرایی[ویرایش]

شیءگرایی در دنیای برنامه‌نویسی هم به همین صورت است. برنامه‌نویس در طول کار خود اشیای مورد نیاز خود را ایجاد می‌کند و یا از اشیای آماده‌ای که توسط برنامه‌نویسان دیگر ایجاد شده است استفاده می‌کند تا با در کنار هم قرار دادن آن‌ها، برنامه‌ای را به‌وجود آورد که از اشیای مختلفی تشکیل شده است. این روش مزیت‌های زیادی دارد که در زیر چند نمونه از اصلی‌ترین آن‌ها را با هم مرور می‌کنیم:

  • بهینه شدن ساختار برنامه:

شیءگرایی باعث تولید برنامه‌های خوش‌ساخت‌تری می‌شود و امکان تغییر و توسعه در برنامه را ساده‌تر می‌کند. مثال: اگر بخواهید قسمت خاصی از برنامه را تغییر دهید، دیگر لازم نیست تمام کدهای برنامه را ویرایش کنید چون می‌دانید که تغییرات شما فقط در همان قسمت مدنظرتان اعمال می‌شود و خللی در کار قسمت‌های دیگر به‌وجود نمی‌آید.

  • استفادۀ مجدد از کدها:

وقتی شما یک شی جدید را خلق می‌کنید؛ می‌توانید تا مدت‌ها از آن استفاده کنید و یا آن را با دیگران به اشتراک بگذارید. این مزیت هنگام ساخت کتابخانه‌های شیءگرا بسیار کارآمد است. به‌عنوان مثال یک دوچرخه می‌تواند تا مدت زمان زیادی به شما سواری دهد. همچنین می‌توانید برای سواری آن را به دوستانتان هم قرض بدهید.

  • کپسوله‌سازی:

در برنامه‌نویسی هر چه اشیای تشکیل دهندۀ یک برنامه از طرز کار یکدیگر بی‌خبرتر باشند، برنامۀ شما ساختار بهتری پیدا خواهد کرد. زیرا در این شرایط اشیا در کار یکدیگر دخالت نمی‌کنند؛ با استفاده از شیءگرایی قسمت‌های مختلف برنامۀ شما از نحوۀ کار همدیگر بی‌خبرند و این مسأله در حالی اتفاق می‌افتد که شما به عنوان برنامه‌نویس از طرز کار آن‌ها اطلاع دارید. مثال: یک نجار می‌داند که فرورفتن میخ در چوب، به خاطر نوک تیز بودن آن است. اما چکشی که روی میخ می‌کوبد از نحوۀ فرورفتن میخ در چوب بی‌خبر است. وظیفۀ چکش فقط کوبیدن میخ است. در حقیقت وظیفۀ چکش فقط کوبیدن است، یک کوبیدن خالص! یعنی بهتر است که چکش حتی از شیءای که به آن نیرو وارد می‌کند هم بی‌خبر بماند. به زبان دیگر چکش فقط باید ضربه بزند، این که شیء ضرب‌دیده میخ باشد یا دیوار، دیگر در حیطۀ معلومات چکش نمی‌گنجد!

  • وراثت:

این قابلیت دقیقاً متناسب با نامش عمل می‌کند. یعنی اگر یک شیء «الف» از شیء «ب» ارث ببرد، یک سری از خصوصیات شیء «ب» به شیء «الف» وارد می‌شود. در برنامه‌نویسی به شیء «الف» فرزند، و به شیء «ب» والد گفته می‌شود.

مثال:

فرزندی که به دنیا می‌آید اصولاً یک سری از خصوصیات ظاهری و یا رفتاری پدر خودش را به ارث خواهد برد

حالا که با تعدادی از مزایای اصلی شیءگرایی آشنا شدید، مطمئناً اشتیاق برنامه‌نویسان به برنامه‌های شیءگرا را درک خواهید کرد.

نتیجه‌گیری[ویرایش]

پایتون یکی از زبان‌هایی است که امکانات شیءگرایی را به صورت توکار (برخلاف C) پیاده‌سازی کرده است. برنامه‌نویسان می‌توانند با استفاده از پایتون به صورت قدرتمندی اقدام به تولید برنامه‌های شیءگرا نمایند. اما به خاطر داشته باشید وجود تفکر شیءگرایی به هنگام برنامه‌نویسی مهم تر از وجود امکانات شیءگرایی در یک زبان خاص است. حالا که با مفهوم شیءگرایی در دنیای حقیقی آشنا شدید می‌توانید با دنبال کردن این سری مقالات، تمام این مفاهیم را با استفاده از پایتون در دنیای برنامه‌نویسی هم پیاده‌سازی کنید. در این مقالات سعی شده است تا جدیدترین روش‌های شیءگرایی در پایتون به شما آموزش داده شود. به همین خاطر ما از کلاس‌های سبک جدید پایتون برای آموزش استفاده کرده‌ایم؛ که به مراتب قابلیت‌های بالاتری نسبت به کلاس های کلاسیک پایتون دارند.

مفهوم کلاس[ویرایش]

مقدمه[ویرایش]

شیءگرایی در برنامه‌نویسی دقیقاً همانند کار با اشیا در دنیای واقعی است. در دنیای واقعی اشیا، قابل لمس و حقیقی هستند. به همین دلیل می‌توانیم خیلی راحت با آن‌ها تعامل برقرار کنیم، اما در دنیای مجازی اوضاع به همین منوال نیست. برای مثال شما نمی‌توانید یک دوچرخه یا یک ماشین را به صورت فیزیکی به برنامه وارد کنید! اما می‌توانید توسط ساختارهای خاص برنامه‌نویسی آن‌ها را با کدهایتان پیاده‌سازی کنید. ساختاری که وظیفۀ پیاده‌سازی اشیا در دنیای برنامه‌نویسی را به عهده دارد، «کلاس» نامیده می‌شود. به زبان ساده‌تر، اشیا در دنیای برنامه‌نویسی به صورت کلاس تعریف می‌شوند.

طرز کار کلاس‌ها[ویرایش]

اما طرز کار کلاس چگونه است؟ کلاس چگونه قادر به پیاده‌سازی اشیا می‌شود؟ جواب آن‌قدرها هم سخت نیست. به حالت عادی هر شیء در دنیای واقعی با سه جنبۀ اصلی شناخته می‌شود:

  • نام شیء
  • وضعیت شیء
  • رفتار شیء

مثلا یک سی‌دی‌پلیر را در نظر بگیرید:

نام این شیء سی‌دی‌پلیر است. این شیء می‌تواند سی‌دی‌ای را اجرا کند، بین آهنگ‌های سی‌دی حرکت کند و غیره... این‌ها رفتاری هستند که از یک سی‌دی‌پلیر بر می‌آید. اما منظور از وضعیت این شیء چیست؟ سی‌دی‌پلیر مقدار بلندی صدا را کنترل می‌کند و یا می‌داند در حال حاضر چه مقدار از ادامۀ آهنگ باقی مانده است. مثلاً می‌گوییم بلندی پلیر در حال حاضر روی درجۀ ۳۰ است. این یعنی وضعیت صدای پلیر ما روی ۳۰ تنظیم شده است.

کلاس‌ها علاوه‌بر این که نامی را برای اشیا در نظر می‌گیرند، می‌توانند وضعیت اشیا را توسط متغیرهای کلاس، و رفتار آن‌ها را توسط متدهای کلاس پیاده‌سازی کنند. متغیرهای کلاس، متغیرهایی هستند که درون بدنۀ آن کلاس تعریف شده‌اند تا نگه‌دارندۀ وضعیت و اطلاعات آن کلاس باشند. متدها هم همان توابع عادی هستند که وقتی در بدنۀ کلاس تعریف می‌شوند، مسئولیت پیاده‌سازی رفتار کلاس را به عهده می‌گیرند. حالا که متوجه طرز کار ساختار کلاس شدید، در قسمت بعد سعی می‌کنیم همین شیء سی‌دی‌پلیر را با این ساختار پیاده‌سازی کنیم.

پیاده‌سازی کلاس‌ها[ویرایش]

در این قسمت قصد داریم ساختار سی‌دی‌پلیر را توسط یک کلاس پیاده‌سازی کنیم. بهتر است ابتدا کدهایمان را بنویسیم و سپس در مورد تک تک خط‌هایمان توضیح دهیم. این فقط یک مثال ساده است پس ما قرار نیست زیاد به جزئیات توجه داشته باشیم. در حال حاظر شما باید سعی کنید بیشتر از طرز کار کدها، به ساختاربندی کدها توجه کنید:

کد کلاس پخش‌کننده سی‌دی تصویری:

class CdPlayer(object):

    def __init__(self):
        self.volume = 20
        self.currentSong = 0

    def setVolume(self, newValue):
        self.volume = newValue

    def play(self, trackNumber):
        #operation for palying songs

    def nextSong(self):
        self.currentSong += 1
        self.play(currentSong)

    def previousSong(self):
        self.currentSong -= 1
        self.play(currentSong)

افراد مبتدی در پایتون به احتمال زیاد از طرز تعریف کردن این کلاس تعجب کرده‌اند. بله تعریف این کلاس با تعریف کلاس‌های عادی پایتون فرق دارد. در مقالۀ اول به شما قول داده شد بود که تمام مباحث این سلسله مقالات بر پایۀ کلاس‌های سبک جدید پایتون (new-style classes) خواهد بود. پس بگذارید قبل از این که به موشکافی مثالمان بپردازیم مقداری هم راجع به کلاس‌های سبک جدید توضیح دهیم.

کلاس‌های سبک جدید

در پایتون تمام اجزای اصلی زبان به صورت اشیا پیاده‌سازی شده‌اند. از متغیرها و توابع و انواع داده‌های اصلی مثل int بگیرید تا خود کلاس‌ها. بله، حتی خود کلاس‌ها هم به‌صورت اشیا تعریف شده‌اند. طبق تصمیماتی که مبنی بر یکپارچه‌سازی اشیای زبان و اشیای تعریف شده از طرف برنامه‌نویسان صورت اتخاذ شد، تمام اشیای اصلی زبان پایتون از یک شیء واحد و برتر به نام object ساخته می‌شوند و یا به عبارت دیگر ارث می‌برند. این مسأله چند سالی است که در پایتون اتفاق افتاده است اما به علت عادت قدیمی برنامه‌نویسان به کلاس‌های عادی و همچنین نبود مستندات کافی برای تشریح کلاس‌های جدید، هنوز کلاس‌های سبک جدید فراگیر نشده‌اند. به هر حال در نسخه‌های آیندۀ پایتون خبری از آن کلاس‌ها قدیمی نیست و این کلاس‌های جدید جایگزین آن‌ها خواهند شد پس بهتر است که در یادگیری آن‌ها عجله کنید.

کلاس‌های شما اگر به صورت عادی تعریف شوند از کلاس‌های کلاسیک و قدیمی پایتون محسوب می‌شوند. اما اگر می‌خواهید کلاس شما به صورت سبک جدید تعریف شود و از مزایای زیاد این گونه کلاس‌ها بهره‌مند شود، باید به هنگام تعریف کلاس خود از شیء برتر object و یا اشیایی که از آن ارث برده‌اند، ارث ببرید. در مورد مسائل مربوط به وراثت و ارث‌بری به مقالات بعدی مراجعه کنید. در ضمن طی این مقالات به‌تدریج با مزایای کلاس‌های جدید آشنا می‌شوید. حالا اجازه بدهید به مثال خودمان برگردیم.

توضیح مثال

در خط اول از مثالمان ما توسط کلید واژۀ class شیئی با نام CdPlayer را تعریف کردیم. و چون این شیء از object ارث برده است پس از کلاس‌های جدید محسوب می‌شود، و امکان استفاده از مزایای آن را خواهد داشت.

در خط بعد شما یک متد مخصوص به نام __init__ را مشاهده می‌کنید. در حالت عادی شما نباید از خود کلاس اصلی استفاده کنید و برای استفاده از آن کلاس باید نمونه‌ای از همان کلاس را ایجاد کنید. در مقالات بعدی با نمونه‌سازی کلاس هم آشنا می‌شوید. اما فعلا همین‌قدر بدانید که هر کلاسی هنگام نمونه‌سازی به طور اتوماتیک عکس‌العملی از خود نشان می‌دهد. این عکس العمل فراخوانی متد ویژۀ __init__ است که برای مقداردهی و اعمال تنظیمات اولیۀ کلاس به‌کار می‌رود. تنظیماتی که ما هنگام ساخت این شیء به آن ها نیاز داشتیم در این متد اعمال شده‌اند. حتما توجه کرده‌اید که لسیت پارامترهای هرکدام از متدهای این کلاس با پارامتر self شروع شده است. self ارجاعی به خود کلاس است و وقتی از self استفاده می‌کنیم یعنی داریم به خود کلاس اشاره می‌کنیم. تمام متدهای تعریف شده در کلاس باید با پارامتر self شروع شوند تا نشان دهند که به کلاس ما وابسته‌اند.

در متد __init__ ما با استفاده از self که به خود کلاس اشاره می‌کند، دو متغیر برای کلاسمان تعریف کردیم. یکی به نام volume که با مقدار ۲۰ ارزش‌دهی شده است و دیگری currentSong که نشان دهندۀ شمارۀ آهنگ فعلی است.

متد بعدی متد setVolume است که باز هم با استفاده از self به متغیر volume اشاره می‌کند و مقدار آن را تغییر می‌دهد. هر وقت بخواهیم از درون یکی از متدهای کلاسمان متغیری را فراخوانی کنیم باید از self برای فراخوانی آن استفاده کنیم. این قانون در مورد فراخوانی متدها هم صادق است.

حالا که متوجه اصل ماجرا شده‌اید حتماً خودتان می‌توانید طرز کار دیگر متدهای کلاس را حدس بزنید. بیایید حدس زدن ساختار بقیۀ متدها را به عنوان تمرین شما به حساب بیاوریم که باید توسط خود شما حل شود. مطمئناً کار ساده‌ای است.

نتیجه‌گیری[ویرایش]

خب تا این جای این سری مقالات شما با شیءگرایی، کلاس‌ها و طرز کار آن‌ها، متغیرها و متدهای کلاس، متد مخصوص __init__ و کلیدواژۀ self آشنا شدید. اما نکته‌ای که باید بدانید این است که این دو مقاله حتی به عنوان یک مقدمه بر مبحث شیءگرایی پایتون هم به حساب نمی‌آیند، پس باید منتظر سری بعدی مقالات باشید. در حقیقت این دو مقاله فقط به عنوان شروعی کوچک بود؛ کار شما تازه از الآن شروع می‌شود!

مفهوم اشیا[ویرایش]

استفاده از اشیا[ویرایش]

در مقالۀ قبل یاد گرفتیم که چگونه باید توسط ساختار کلاس، اشیا خود را بسازیم. در این مقاله قصد داریم نحوۀ استفاده از اشیایی که ساخته‌ایم را به شما آموزش دهیم. برای این کار باید اشیای خود را نمونه‌سازی کنیم یعنی به زبان ساده‌تر از شیء اصلی خود یک کپی بسازیم. مثلا شما هنگامی که نیاز به استفاده از شناسنامۀ خود داشته باشید، اصولاً سعی می‌کنید از کپی آن استفاده کنید و اصل شناسنامه را با خود حمل نکنید. در مورد اشیا هم این قانون حاکم است. شما می‌توانید تا هر چقدر که دلتان بخواهد از روی شیء اصلی خود نمونه‌سازی کنید.

این نمونه‌ها به صورت کاملاً مستقل عمل می‌کنند. مثلا اگر از روی شیء CdPlayer که در مقالۀ قبل ایجاد کردیم دو نمونه به نام‌های myPlayer1 و myPlayer2 بسازیم، هیچ‌کدام از این اشیا به هنگام استفاده در کار یکدیگر دخالتی نمی‌کنند. میزان صدا می‌تواند برای myPlayer1 روی ۴۰ تنظیم شود در حالی که میزان بلندی صدای myPlayer2 روی ۶۰ تنظیم شده است.

برای نمونه‌سازی از یک کلاس باید به صورت زیر عمل کرد:

ایجاد یک موجودیت از کلاس سی‌دی پلیر:

myPlayer1 = CdPlayer()
    myPlayer2 = CdPlayer()

با این روش دو نمونۀ کاملاً مستقل از روی CdPlayer ایجاد می‌شود. اگر دقت کنید می‌بینید که ما شیء CdPlayer را به همراه پرانتز احضار کردیم. این یعنی اینکه ما میتوانیم هنگام نمونه سازی از CdPlayer پارامترهایی را نیز را مشخص کنیم. این پارامترها مستقیماً به متد مخصوص __init__ که در بدنۀ کلاس تعریف شده است فرستاده می‌شوند. همان‌طور که قبلا گفته بودیم هر کلاس به هنگام نمونه‌سازی خود یک بار این متد را صدا می‌زند. در مورد شیء CdPlayer چون هیچ آرگومان خاصی در متد __init__ مشخص نشده بود پس لازم نیست به هنگام نمونه‌سازی از روی این شیء پارامتری را به آن بفرستیم.

فراخوانی خصوصیات اشیا[ویرایش]

حالا ما دو نمونه از شیء CdPlayer در اختیار داریم. برای ارتباط برقرار کردن با اشیا باید از خصوصیات آن‌ها استفاده کرد. خصوصیات همان متغیرها و متدهای تعریف شده برای اشیا هستند. مثلاً اگر لازم باشد myPlayer1 آهنگ سوم از سی‌دی فرضی ما را با بلندی صدای ۵۰ درجه اجرا کند باید اعمال زیر را انجام دهیم:

فراخوانی خصوصیات اشیا سی‌دی پلیر:

myPlayer1.volume = 50
myPlayer1.play(3)

در مثال بالا ما ابتدا توسط عملگر نقطه ( . ) خصوصیت volume را با ۵۰ تنظیم کردیم. سپس به همین طریق با فراخوانی متد play ، آهنگ سوم از سی‌دی فرضی خود را اجرا کردیم. البته برای تنظیم صدا می‌توانستیم از متد setVolume هم استفاده کنیم که کاری مشابه با همین عمل ما را انجام می‌داد. حالا اگر بخواهیم به آهنگ بعدی پرش کنیم فقط کافی است متد nextSong را صدا بزنیم:

پخش آهنگ بعدی سی‌دی:

myPlayer1.nextSong()

همان‌طور که می‌بینید ساختار کلاس طوری شیء سی‌دی پلیر را پیاده‌سازی کرده است که انگار ما در حال استفاده از یک سی‌دی پلیر واقعی هستیم و متدهایی مثل play هم همانند دکمه‌های این سی‌دی پلیر عمل می‌کنند.

وراثت چیست؟[ویرایش]

به صورت گذرا در مقاله‌های قبلی به وراثت اشاره کرده بودیم اما در این مقاله می‌خواهیم این موضوع را یه کمی بیشتر موشکافی کنیم. وراثت از معدود کلمات کامپیوتری به حساب می‌آید که معنی آن دقیقاً برابر با همان معنی انگلیسی‌اش است. یعنی وقتی می‌گوییم کلاس B از کلاس A ارث می‌برد، یعنی به طور اتوماتیک یک سری از خصوصیات A در کلاس B گنجانده می‌شود. درست مانند کودکی که امکان دارد رنگ چشم یا موهایش را از خانواده‌اش به ارث ببرد.

به مثال زیر توجه کنید:

class A(object):

        def sayHello(self):
            print "Hello A!"

class B(A):
    pass

b = B()
b.sayHello()

در مثال بالا A کلاسی است که یک متد تعریف شده به نام sayHello را در خود جای داده است. هنگام تعریف کلاس B ما مشخص کردیم کردیم که این کلاس باید از A ارث ببرد، بنابراین به طور اتوماتیک متد sayHello که اصلاً در B وجود ندارد، به کلاس B اضافه می‌شود.

اگر متدی با همین نام در کلاس B هم تعریف شده بود، متد sayHello که مربوط به کلاس A است اجرا نمی‌شد و هنگام فراخوانی، از متد تعریف شده در کلاس B استفاده می‌شد. در چنین وضعیتی می‌گوییم متد sayHello ی موجود در کلاس B ، متد sayHello ی موجود در کلاس A را لغو کرده است. باید به این نکته توجه کنیم که چون خود A از شی اصلی object ارث برده است، پس تمام کلاس‌هایی که از آن ارث میبرند – مانند B – هم خود به خود در دستۀ کلاس‌های سبک جدید پایتون جای می‌گیرند.

استفاده از متدهای لغو شده[ویرایش]

همان‌طور که در بالا اشاره کردیم اگر کلاس B متدی از کلاس A را لغو کند، دیگر توانایی صدا کردن آن را از طریق کلاس B را نخواهیم داشت چون به حالت عادی متدی که مال خود کلاس B است اجرا می‌شود. اما در شرایطی خاص ممکن است نیاز به فراخانی متد لغو شدۀ کلاس A باشد. برای این کار باید مانند مثال زیر عمل کنیم:

class A(object):

    def sayHello(self):
        print "Hello A!"

class B(A):

    def sayHello(self):
        print "Hello B!"
        A.sayHello(self)

b = B()
b.sayHello()

همان‌طور که می‌بینید باید برای استفاده از متدهای لغو شدۀ کلاس والد، مستقیماً به خود آن کلاس اشاره کنیم و به عنوان اولین پارامتر آن متد، از ارجاع self استفاده نماییم.

نکته‌ای در رابطه با سازنده‌ها[ویرایش]

در بسیاری از زبان‌های برنامه‌نویسی شیءگرا، وقتی کلاس فرضی B از کلاس فرضی A ارث می‌برد، به طور خودکار متد سازندۀ کلاس A را اجرا می‌کند. اما در پایتون اگر برای کلاس A متد __init__ را تعریف کرده باشیم باید به صورت دستی آن را اجرا کنیم زیرا در غیر این صورت کلاس A مقداردهی اولیه نمی‌شود.

به مثال زیر توجه کنید:

class A(object):
    def __init__(self):
        self.name = "amir"

class B(A):
    def __init__(self):
        A.__init__(self)

    def sayHello()
        print self.name

bb = B()
bb.sayHello()

در این مثال به صراحت متد __init__ کلاس A را در متد __init__ کلاس B فراخوانی کردیم ولی شاید به نظر برسد که اگر آن را فراخوانی نمی‌کردیم دیگر متغیر name در کلاس A به‌وجود نمی‌آمد و کلاس B نمی‌توانست با استفاده از قابلیت‌های ارث‌بری آن را به‌کار گیرد. ولی در متد __init__ کلاس B به طور خودکار متد __init__ کلاس پدر یعنی کلاس A صدا زده می‌شود.

سربارگذاری عملگر[ویرایش]

امکان سربارگذاری عملگرها در پایتون این توان را به کاربر می‌دهد که تعیین کند انواع جدید با عملگرهای موجود چگونه استفاده شوند. عملگرهای قابل سربارگذاری در پایتون از قرار زیر هستند:

+    -      *       **      /       //      %       <<
>>  &        |       ^       ~      <        >      <=
>=  ==      !=      +=      -=      *=      **=     /=
//=         %=      <<=     >>=     &=      ^=      |=      []
()  .       ‘‘      in

البته باید توجه داشت که در عمل سربارگذاری نمی‌توان خواص عملگرها مانند اولویت‌ها ، دودویی یا یکانی، شرکت‌پذیری و ... را تغییر داد، یا به خلق عملگر جدیدی پرداخت؛ برخی عملگرها دونوع دودویی و یکانی دارند که هر کدام به‌طور جداگانه تعریف خواهند شد. به ازای هر عملگر در کلاس شیء یک یا چند متد ویژه وجود دارد، زیرا سربارگذاری عملگرها از جمله خواصی است که زندگی در پایتون منوط به داشتن آن‌ها است. در زیر عملگرها را مشاهده می‌کنید.

عملگرهای دودویی:[ویرایش]

+    __add__, __radd__
-   __sub__, __rsub__
*   __mul__, __rmul__
/   __div__, __rdiv__, __truediv__, __rtruediv__
//  __floordiv__, __rfloordiv__
%   __mod__, __rmod__
**  __pow__, __rpow__
<<  __lshift__, __rlshift__
>>  __rshift__, __rrshift__
&   __and__, __rand__
^   __xor__, __rxor__
|   __or__, __ror__
+=  __iadd__
-=  __isub__
*=  __imul__
/=  __idiv__, __itruediv__
//=         __ifloordiv__
%=  __imod__
**=         __ipow__
<<=         __ilshift__
>>=         __irshift__
&=  __iand__
^=  __ixor__
|=  __ior__
==  __eq__
!+, <>      __ne__
>   __gt__
<   __lt__
>=  __ge__
<=  __le__

در لیست فوق اسامی در سه حالت به چشم می‌خورند، با پیشوند r ،i و بدون پیشوند. متدهای بدون پیشوند برای حالت عادی عمل، که دو شیء از یک نوع با هم وارد عمل می‌شوند؛ تعریف می‌شود. یعنی برای عبارت a+b که در آن a و b از یک نوع هستند، متد a.__add__(b) صدا زده می‌شود.

پیشوند r برای حالتی است که در عبارت a+b``، ``a از نوع b نباشد. در این حالت چون b شیء جدید است و a نوع b را نمی‌شناسد، بر خلاف معمول عملوند سمت راست عبارت مسئول انجام عمل جمع است. به همین دلیل از پیشوند r استفاده می‌شود.

پیشوند i برای اعمال فوری (in-place) است. یعنی وقتی داریم a+=b متد همۀ اعمال لازم را روی اشیاء درگیر در عمل انجام داده و مقدار جواب نهایی را برمی‌گرداند. در مورد این مقوله در آینده توضیح خواهیم داد.

برای بارگذاری عملگرهای دودویی، متدهای ویژۀ آن‌ها را با امضای زیر در کلاس شیء مورد نظر تعریف خواهیم کرد.

def __methodName__(self, other):

عملگرهای یكانی قابل بارگذاری، از این قرارند:

~,  __invert__
-,   __neg__
+,  __pos__

عملگرهای یکانی این‌گونه تعریف می‌شوند:

def __methodName__(self):

مثال نقطۀ هندسی

class point:
    """ A geometric 2Dimensional point """

    def __init__(self, Xvalue = 0, Yvalue = 0):

        self.x = float(Xvalue)
        self.y = float(Yvalue)
    #adding conversion to type string (partially for printing the point)
    def __str__(self):
        print "converting point to string"
        return '(%s, %s)'% \
            (str(self.x), str(self.y))
    #adding binary '+' operator
    def __add__(self, other):
        print "adding two points"
        return point(self.x + other.x , self.y + other.y )
    #adding unary '+' operator
    def __pos__(self):
        print "making point positive"
        return point (abs(self.x), abs(self.y))
    #adding unary invert operator
    def __invert__(self):
        print "inverting a point"
        return point(self.y, self.x)

#adding in-place addition ability
def __iadd__(self, other):
        return point(self.x + other.x, self.y + other.y)

و مشاهدۀ چگونگی عملکرد آنها:
<source lang="python">
>>> p1 = point(-1,-1)
>>> p2 = point(3,4)
>>> print (+p1) + ~p2
making point positive
inverting a point
adding two points
converting point to string
(5.0, 4.0)
>>> p1 += p2
>>> print p1
converting point to string
(2.0, 3.0)

منابع[ویرایش]