علی
علی
خواندن ۶ دقیقه·۳ سال پیش

ـ interface ها و abstract کلاس ها قطعات گمشده در پایتون قسمت ۱


ـ interface ها داخل پایتون کجان اصلا چرا همچین چیزی تو پایتون نیستش ؟

جاگزینی براش وجود داره؟ اصلا میشه شبیه سازیش کرد

احتمالا تا الا حدسای زدید. ولی قبل از اینکه شروع کنم بیاید ببینیم چرا interface ها درست شدن تو زبان های خانواده C ولی تو زبان های مثل پایتون وجود ندارن و اصلا ی سوال مهمتر تفاوت شون با abstract کلاس ها چین ؟

سوال میدونید اصلا abstract کلاس ها چی هستن ؟ خب اگه نمیدونید صبر کنید اوناروم هم توضیح میدم.

چیشد interface ها درست شدن ؟

کل موضوع برمیگرده به Object Oriented یا به اختصار شی گرایی

خب برای جواب دادن این باید بریم ساختار زبان های مثل جاوا و بقیه فک فامیل های C ی نگاهی بندازیم D:

تو این زبانا یک مشکل بزرگ وجود داره و اونم single-inheritance یا بقولی تک ارثی بودن هستش یعنی چی ؟

فرض کنید ما یک کلاس داریم و میخوایم همزمان از دوتا کلاس یا بیشتر ارث بری بکنیم خب اینکار تو این زبانا غیرممکن هستش ولی خب پایتون اینجا هیچ کم کسری نذاشته .

ی مثال از زبان جاوا ببینیم تا خوب متوجه بشید.

نکته : برای شرح مفاهیم اولیه از زبان جاوا استفاده میشه چون بصورت ملموس تری میتونین حس کنید مفاهیم مورد نظرو برعکس پایتون
inheritance in java
inheritance in java

ی توضیح کوچیک درمورد کد بالا :

اول دوتا کلاس داریم که قرار ازشون ارث بری بشه به اسم ها parent_1 و parent_2 و سومین کلاس هم به اسم child_1 اومد از کلاس parent_1 ارث بری کرده که پیتونید کلمه کلیدی extends که معنی اینو میده از این کلاس ارث بری کن ببینید خب تا اینجا همه چیز اوکیه ولی child_2 اومد ارث بری کرده از دوتا کلاس parent ما خب همینطور که خودتون میدونید کار بدی هستش اینقدر طمعه داشته باشید به همون سهم خودتون قانع باشید D:

اگه اینکارو که کلاس child_2 کرده تو زبان جاوا و بقیه فک فامیل های C بکنید با یکسری ارور های ناموسی مواجه میشید.

ولی خب همینطور که مستحضرید پایتون اینارو به کتف چپش گرفته همینطور که تو کد پایین هم مشاهده میکنید.

 inheritance in python
inheritance in python

خب تا الا حتما متوجه شدید نمیشه تو این زبانهای که گفتم بیشتر از یک کلاس ارث بری کرد برعکس زبان های مثل پایتون که چند ارثی ساپورت میکنن خب راحل چیه؟

راحل interface ها بودن به کلاس های فرزند اجازه میدادن همزمان از دو یا چندتا والد ارث بری کنن.

تیکه کد پایین ببینید

تو چند خط اول سه تا interface تعریف کردیم به اسم های parent_1 , parent_2 , parent_3 و بعد از اون دوتا کلاس تعریف شدن به اسم های child_1 , child_2 و برای اینکه یک کلاس بتونه از interface ها ارث بری بکنه از کلمه کلیدی implements بعد اسم کلاس استفاده میشه . همینطور که میبنید هیچ محدودیتی برای ارث بری کردن نیست از interface ها برعکس کلاس های معمولی

دقیقا interface ها چه کاربردی دارن؟

اینکه چه کاربردی دارن مهمتریشو بالاتر گفتم ولی این همه ماجرا نیست.

کاربرد دیگه این interface ها بخوایم خودمونی بگیم یک لیست از چیزای هستش که والد (parent) از فرزندش (child) انتظار داره که حتما داشته باشه وگرنه خیلی ناراحت میشه و فرزندشو از ارث محروم میکنه D:

حالا ی مثال از دنیای واقعی درمورد شی گرایی و ارث بری هاشون براتون میزنم

ما یک شی والد داریم به اسم خونه این خونه ما برای اینکه بشه خونه درنظرش گرفته یکسری چیز میز نیاز داره تا بشه بهش گفت خونه مثلا چی ؟ اینم من باید بگم ؟ :|

جدای از شوخی میشه گفت اتاق نیازه داره, اشپزخونه, نشیمن و سرویس بهداشتی بصورت عمومی اینا اجزای معمول یک خونه هستن پس وقتی میگیم خونه یک مجموعه از این اجزا به اضافه چیزای غیر معمول منظورمون هستش که یک خونه میتونن تشکیل بدن

حالا یک شی فرزند داریم که از والد خونه از نوع interface ارث بری کرده به اسم خونه ممد. این خونه ممد حتما چیزای که والد خونه لیست کرده حتما باید داشته باشه ولی یک نکته مهم ! والد خونه هیچ نظر و ایده ای نداره که این اجزا چه شکلی باشن میتونه نشیمن دویست متری باشه یا ده متری فقط بخش مهمش این هستش که حتما باید داشته باشه اونو و اگه نداشته باشه دیگه نمیشه اونو خونه گفت برای همین هیچ ارثی که بهش نمیرسه هیچ چندتا ارور هم میگیره .

اگه از یک interface ارث بری کردید و متد های اونو تو کلاس فرزند استفاده نکردید با ارور مواجه میشید

کد بالا اگه اجرا کنید به مشکل میخورید چرا؟ چون تو interface لیست توابعی که باید پیاده سازی بشن گفتیم ولی تو کلاس فرزند اونارو استفاده نکردیم

خب از روی همین نکته بالا متونیم متوجه بشیم چرا اینقدر بدرد بخورن ! بازم بخوبی نفهمیدید کجا این مورد بدرد میخوره؟ خب فرض کنیم رفتید خونه ممد ازش میپرسید ممد سرویس بهداشتی کجاست ممد در کمال ناباوری میگه خونه من سرویس بهداشتی نداره :| خب اونجاست که آب روغن قاطی میکنید D:

میبنید بعضی مواقع ما از فرزند ها یکسری انتظاراتی داریم که بطور معمول باید داشته باشنش که به مشکلی برنخورید مثل زمانی که داشتید از خونه ممد استفاده میکردید ! اگه موقع ساخت خونه ممد از یک والد interface به اسم خونه پیروی میکرد مهندسه خونه ممد حتما سرویس بهداشتی میساخت چون تو interface خونه ذکر شده بود که حتما باید اونو داشته باشه اگه یک فرزند از اونه.

بطور خلاصه میشه گفت دلیل دوم درست کردن یک نقشه از چیزای هستش که ما نیاز داریم .

میرسیم به محدودیت های interface ها و تشابه اونها با abstract کلاس ها .

در واقع خیلی interface ها با abstract کلاس ها تشابه دارن و چیزی که این دوتا از هم جدا میکنه همین محدودیت ها هستن

  • اولین محدودیت و مهمترینش متد هایکه تو interface ها نوشته میشن همیشه خالی هستن !! و باید از طریق فرزند بازنویسی بشن برعکس abstract کلاس ها
  • دومین چیز این هستش که تو کلاس های abstract هم متد های abstract هستن و هم متد های معمولی برعکس interface ها

همینطور که تو کد بالا میبینید کلاس abstract ما محدودیتی برای نوع توابع درونش نداره و از هر دو نوع ساپورت میکنه هم از توابع abstract و هم توابع معمولی

  • سومین چیز این هستش که هیچ شی مستقیمی از interface ها و abstract ها نمیشه ساخت و حتما فقط به عنوان والد استفاده بشن
تو کد بالا میبنید که یک نمونه بصورت مستقیم از یک interface خواسته ساخته بشه ولی اینکار غیرممکن هستش و ارور میگیرید برای کلاس های abstract هم به این شکل هستش ولی برای کلاس های عادی نه!
  • چهارمین چیز اینکه abstract کلاس ها بازم کلاس هستن ! پس نمیشه بیشتر از یک دونش برای ارث بری استفاده کرد و بازم به مشکل single-inheritance میخوریم
  • پنجم اینکه تمام توابع interface ها از نوع abstract هستن برای همین تو خالی هستن و از طریق کلاس فرزند پر میشن
  • و اخرین تفاوت interface ها متد سازنده ای یا constructor تو جاوا و یا متد __init__ تو پایتون ندارن برعکس abstract کلاس ها که میتونن داشته باشن!

خب بریم interface هارو تو پایتون ببینیم !

قبل شروع چندتا نکته بگم اول اینکه اومدیم interface ها و یکسری اطلاعات درموردشون گفتیم ولی باید اینو بدونید که خیلی از محدودیت های که بالاتر گفتم به این شکل تو پایتون نیستن! یعنی چی ؟! یعنی اون مفهموم interface هایکه تو زبان جاوا و بقیه خانواده C میبینیم تو پایتون به اون شکل نیست , مثلا همینطور که بالاتر گفتم پایتون یک زبانی هستش که قابلیت پشتیبانی از چند وراثتی داره برای همین ما چیزی به اسم interface ها نداریم که بیاد مشکل اینکه نمیتونیم همزمان از چند کلاس وراثت بگیریم حل بکنه یا جاگزین abstract کلاس ها بشه. برای همین ما از abstract کلاس ها استفاده میکنیم تو پایتون ولی یک مشکلی این وسط هستش ! ما abstract کلاس هارو هم تو پایتون نداریم D:

ولی یکسری راحل های برای پیاده سازی اونها تو پایتون وجود داره تو قسمت بعدی دربارش میگم و نشونتو میدم چطور میتونید ازشون استفاده کنید

برای همین تو قسمت اول از زبان جاوا برای نشون دادن این مفاهیم استفاده کردم و گفتم این مفاهیم تو پایتون بصورت ملموس قابل درک نیستن.

ولی یکسری راحل های برای پیاده سازی اونها تو پایتون وجود داره تو قسمت بعدی دربارش میگم و نشونتو میدم چطور میتونید ازشون استفاده کنی

یک فرد آزاد از خودش . github.com/bigsbug
شاید از این پست‌ها خوشتان بیاید