شی گرایی در پایتون چیست؟ – به زبان ساده + مثال و تمرین

۹۱۱۷ بازدید
آخرین به‌روزرسانی: ۱۰ اردیبهشت ۱۴۰۳
زمان مطالعه: ۲۷ دقیقه
شی گرایی در پایتون چیست؟ – به زبان ساده + مثال و تمرین

«شی گرایی» یا «برنامه نویسی شی گرا» (Object-Oriented Programming | OOP) یکی از رویکردهای مهم در برنامه نویسی است که بسیاری از برنامه‌نویسان با استفاده از این رویکرد به توسعه پروژه‌های خود می‌پردازند. این شیوه شامل مفاهیم کلیدی و اصول خاصی می‌شود که باید از آن‌ها در پیاده‌سازی برنامه‌های مبتنی بر این روش استفاده شود. زبان برنامه نویسی پایتون از جمله محبوب‌ترین و پرکاربردترین زبان‌های برنامه نویسی به حساب می‌آید که شی‌گرا هم هست و به خوبی می‌توان اصول شی‌گرایی را در آن پیاده‌سازی کرد. بنابراین در مطلب حاضر، سعی بر این است به شی گرایی در پایتون بپردازیم و مثال‌های کاربردی را از این زبان ارائه کنیم تا مخاطبان با رویکرد برنامه نویسی شی گرا در پایتون آشنا شوند.

فهرست مطالب این نوشته
997696

شی گرایی در پایتون چیست ؟

رویکرد برنامه نویسی شی گرا، بر پایه دو مفهوم اصلی «شی» (Object) و «کلاس» (Class) شکل گرفته است که با این دو مفهوم می‌توان اطلاعات تمام «ماهیت‌های» (Entity) دنیای واقعی را در برنامه به راحتی ذخیره کرد.

به بیان جزئی‌تر می‌توان گفت هدف از شی گرایی در پایتون ساخت کلاسی است که دربرگیرنده تمامی «ویژگی‌ها» (Properties) و «رفتارها | متدهای» (Methods) مرتبط با یک ماهیت باشد و از طریق ایجاد شی از کلاس مربوطه بتوان به همه «مشخصه‌ها» (Attributes) یا همان ویژگی‌ها و متدها دسترسی داشت.

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

مثال شی گرایی در پایتون چیست

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

شی و کلاس در پایتون

انواع داده‌های پایتون نظیر اعداد، رشته‌ها و لیست‌ها به منظور ذخیره مقادیر ساده‌ای از اطلاعات ایجاد شده‌اند. به عنوان مثال، با تعریف متغیرهایی با نام‌های Price و ColorName از نوع عددی و رشته‌ای، می‌توان به ترتیب، قیمت یک سیب و رنگ آن را ذخیره کرد.

حال فرض کنید قصد دارید با اطلاعات پیچیده‌تری در برنامه نویسی کار کنید. به عنوان مثال، مدیر شرکت از شما می‌خواهد اطلاعات شخصی کارمندان را در یک فایل ذخیره کنید. این اطلاعات می‌تواند شامل نام کارمندان، سن، سِمَت شغلی و تاریخ شروع به کار آن‌ها باشد.

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

1kirk = ["James Kirk", 34, "Captain", 2265]
2spock = ["Spock", 35, "Science Officer", 2254]
3mccoy = ["Leonard McCoy", "Chief Medical Officer", 2266]

با این که چنین روشی برای ذخیره اطلاعات کارمندان، ساده است، اما مشکلات مهمی دارد. چنانچه بخواهید به اطلاعات هر شخص در برنامه دسترسی داشته باشید، باید از اندیس استفاده شود. به عنوان مثال، اندیس صفر از لیستkirk ، نام کارمند را مشخص می‌کند.

زمانی که قطعه کدهای برنامه شما زیاد شوند و چندین برنامه نویس بخواهند با چنین روشی به داده‌ها دسترسی پیدا کنند، روش دسترسی به اطلاعات با استفاده از اندیس، مناسب نیست، زیرا افراد برنامه نویس باید به‌طور مداوم لیست اطلاعات کارمندان را چک کنند و از این مسئله مطمئن شوند که چه اندیسی، در برگیرنده چه اطلاعاتی از کارمندان است.

به علاوه، چنانچه اطلاعات کارمندان کامل نباشد، طول لیست‌های تعریف شده برای هر یک از کارمندان یکسان نخواهد بود و شماره اندیس‌های مشابه تمامی لیست‌ها، به اطلاعات یکسانی اشاره نخواهند داشت. در مثالی که ارائه کردیم، اندیس ۱ در لیست‌هایkirkوspockبه سن ۲ کارمند اشاره دارد، اما در لیستmccoy، آیتمی برای سن کارمند لحاظ نشده است و اندیس ۱ از این لیست، عنوان شغلی کارمند را نشان می‌دهد.

برای رفع چنین مشکلات مهمی، می‌توان از شی گرایی در پایتون استفاده کرد و اطلاعات کلیه کارمندان را با تعریف یک کلاس و ساخت اشیای مختلف برای هر یک از کارمندان در برنامه ذخیره کرد.

مفاهیم کلاس و شی در شی گرایی پایتون

به عبارتی می‌توان گفت شی گرایی در پایتون این امکان را فراهم می‌کند تا با استفاده از کلاس، بتوان ساختار داده جدیدی را تعریف کرد و برای آن ویژگی‌ها و متدهای مختلفی در نظر گرفت. کلاس، طرح اولیه‌ای از هر ماهیت است و داده‌ای را در خود ذخیره نمی‌کند. به منظور ذخیره کردن داده‌ها با استفاده از کلاس، باید «نمونه‌ای» (وهله | Instance) از کلاس ساخته شود تا بتوان داده‌های خود را در آن ذخیره کرد. به هر نمونه ایجاد شده از کلاس، شی گفته می‌شود. در واقع کلاس «نقشه ساخت» شی به حساب می‌آید.

در مثالی که برای ذخیره اطلاعات کارمندان ارائه کردیم، می‌توان کلاسی را با نام Person ایجاد کرد که درون این کلاس می‌توان ویژگی‌های مربوط به کارمندان مانند اسم، سن، آدرس، سمت شغلی و تاریخ شروع به کار را تعریف کرد. همچنین عملیات و توابعی که اشیای کلاس کارمند می‌توانند پیاده‌سازی کنند را نیز مِتُدهای کلاس می‌نامند و این متدها در واقع رفتار اشیای مشتق شده از کلاس را مشخص می‌کنند. سپس، به منظور ذخیره داده‌های هر یک از کارمندان، باید از شی استفاده کرد. در ادامه، به نحوه ساخت کلاس و شی در زبان برنامه نویسی پایتون پرداخته می‌شود.

نحوه تعریف کلاس و شی در پایتون

همان‌طور که پیش از این اشاره کردیم، برای استفاده از شی گرایی در پایتون باید در وهله اول، کلاسی برای ماهیت تعیین شده ایجاد کرد.

به منظور تعریف کلاس در پایتون، از کلمه کلیدی class استفاده می‌شود. پس از نوشتن این کلمه کلیدی، باید نام کلاس درج شود. برای نوشتن حرف اول نام کلاس باید از حروف بزرگ انگلیسی استفاده کنیم. در نهایت، علامت دو نقطه (: ) پس از نام کلاس قرار می‌گیرد. در ادامه، مثالی از نحوه ساخت کلاس برای کلاس Personملاحظه می‌شود.

1class Person:
2    pass

چنانچه نام کلاس از چندین کلمه تشکیل شده باشد، باید کلمات بدون درج فاصله به گونه‌ای نوشته شوند که حروف نخست کلمات، حروف بزرگ انگلیسی باشند. به عنوان مثال، اگر قصد دارید کلاسی برای کارمندان بخش فروش سازمان بسازید، می‌توانید از نام SalesEmployee استفاده کنید.

از کلمه کلیدی pass در توابع و کلاس‌هایی استفاده می‌شود که دستورات در بدنه آن‌ها نوشته نشده باشند. نوشتن این کلمه کلیدی باعث می‌شود در زمان اجرای برنامه، خطای کامپایلر رخ ندهد. پس از ساخت کلاس، می‌توان شیئی را به عنوان وهله‌ای از کلاس ساخت. در بخش پیشین، از متغیری با عنوان kirkبرای ذخیره اطلاعات یکی از کارمندان استفاده کردیم. از همین نام برای ساخت یک شی جدید از کلاس Personبه روش زیر استفاده می‌کنیم:

1class Person:
2    pass
3
4kirk = Person()

چنانچه کلاس Personدارای ویژگی‌ها و متدهای مختلف باشد، با استفاده از شی kirkمی‌توان به هر یک از آن‌ها دسترسی داشت و اطلاعات کارمند kirkرا با استفاده از ویژگی‌ها و متد کلاس Personذخیره کرد. با استفاده از دستور type() نیز می‌توان کلاس شی تعریف شده را مشخص کرد. در مثال زیر، نحوه کاربرد این تابع ارائه شده است:

1print(type(kirk))

خروجی قطعه کد بالا به صورت <class '__main__.Person'>  است که این خروجی نشان می‌دهد شی kirkبه عنوان نمونه‌ای از کلاس Personمحسوب می‌شود. پس از ساخت کلاسPersonو تعریف شی از این کلاس، می‌توان با استفاده از تابعisinstance()مشخص کرد که آیا شی، نمونه‌ای از کلاسPersonاست؟ قطعه کد زیر، نحوه استفاده از این تابع را نشان می‌دهد.

1kirk = Person()
2print(isinstance(kirk, Person))  # True

خروجی قطعه کد بالا برابر با True‌ است که این مقدار نشان می‌دهد شیkirk، نمونه‌ای از کلاسPersonمحسوب می‌شود. در ادامه مطلب، به نحوه تعریف ویژگی‌ها و متدهای کلاس در زبان پایتون پرداخته می‌شود.

 

تعریف ویژگی های کلاس در پایتون

شی گرایی در پایتون این امکان را برای برنامه‌نویسان فراهم می‌کند تا ویژگی‌های مختلفی را درون کلاس ایجاد کنند. برای ساخت ویژگی می‌توان از تعریف متغیر استفاده کرد.

دو نوع ویژگی می‌توانیم در کلاس پایتون بسازیم که در ادامه به آن‌ها اشاره شده است:

  • «متغیرهای کلاس» (Class Variables)
  • «متغیرهای وهله‌ای» (Instance Variables)

در ادامه مطلب، به توضیح هر یک از این دو نوع متغیر و نحوه ساخت آن‌ها در پایتون پرداخته می‌شود.

متغیر کلاس در پایتون چیست ؟

متغیرهای کلاس، نوعی از ویژگی‌های درون کلاس هستند که پس از اعلان کلاس تعریف می‌شوند. این متغیرها خارج از توابع (متدهای) داخل کلاس قرار می‌گیرند. مقادیر این نوع متغیرها برای تمامی اشیای ساخته شده از کلاس، به اشتراک گذاشته می‌شوند.

در قطعه کد زیر، متغیر‌های extension وversion مثال‌هایی از متغیرهای کلاسHtmlDocument هستند.

1class HtmlDocument:
2    extension = 'html'
3    version = '5'

به منظور دسترسی به مقادیر متغیرهای کلاس، می‌توان از نام کلاسHtmlDocumentبه همراه علامت نقطه (. ) و سپس نام متغیر کلاس استفاده کرد.

1class HtmlDocument:
2    extension = 'html'
3    version = '5'
4
5print(HtmlDocument.extension) # html
6print(HtmlDocument.version) # 5

همچنین، می‌توان شیئی از کلاسHtmlDocumentساخت و با استفاده از نام شی به متغیرهای کلاس دسترسی داشت.

1class HtmlDocument: 
2    extension = 'html' 
3    version = '5' 
4
5object = HtmlDocument() 
6print(object.extension) # html 
7print(object.version) # 5

چنانچه، نام متغیر کلاسی را به اشتباه فراخوانی کنیم و آن متغیر در کلاس تعریف نشده باشد، خطای کامپایلر رخ می‌دهد.

1class HtmlDocument: 
2extension = 'html' 
3version = '5' 
4
5print(HtmlDocument.media_type) 

در قطعه کد بالا، متغیرmedi_TYPEدر کلاسHtmlDocumentتعریف نشده است. به همین خاطر، در زمان اجرای قطعه کد بالا، خطای زیر رخ می‌دهد:

AttributeError: type object 'HtmlDocument' has no attribute 'media_type'

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

1class HtmlDocument:
2    extension = 'html'
3    version = '5'
4
5extension = getattr(HtmlDocument, 'extension')
6version = getattr(HtmlDocument, 'version')
7
8print(extension)  # html
9print(version)  # 5

به منظور تغییر مقادیر متغیرهای کلاس می‌توان از نام کلاس و نام شی به روش زیر استفاده کرد:

1HtmlDocument.version = 10
2object.version = 10

به علاوه،‌ تابعsetattr()را نیز می‌توان برای تغییر مقادیر متغیرهای کلاس به کار برد. در قطعه کد زیر، نحوه استفاده از این تابع نشان داده شده است.

1setattr(HtmlDocument, 'version', 10)

به منظور اضافه کردن متغیرهای کلاس جدید می‌توان از سه روش استفاده کرد. روش اول، اضافه کردن نام متغیر کلاس به همراه مقدار آن درون کلاس تعریف شده است. در روش دوم، می‌توان از بیرون کلاس، متغیر کلاس جدیدی را به کلاس تعریف شده از قبل، به روش زیر اضافه کرد:

1HtmlDocument.media_type = 'text/html'
2print(HtmlDocument.media_type) # text/html

روش سوم برای اضافه کردن متغیر کلاس جدید به کلاس از پیش تعریف شده، استفاده از تابعsetattr()است. در قطعه کد زیر، نحوه استفاده از این تابع نشان داده شده است:

1setattr(HtmlDocument, media_type, 'text/html')
2print(HtmlDocument.media_type) # text/html

شی گرایی در پایتون این امکان را به برنامه‌نویسان می‌دهد تا وقتی به متغیر کلاسی احتیاج نداشتند، آن متغیر را با استفاده از تابعdelattr()و کلمه کلیدیdelاز برنامه حذف کنند. در قطعه کد زیر، نحوه استفاده از این دو روش برای حذف متغیرهای کلاسHtmlDocumentملاحظه می‌شود.

1delattr(HtmlDocument, 'version')
2del HtmlDocument.extension

متغیرهای وهله ای در کلاس های پایتون

متغیرهای نمونه، متغیرهایی هستند که درون توابع (متدها) و «سازنده‌ها» (Constructors) تعریف می‌شوند. مقادیر این متغیرها برای هر یک از اشیای ساخته شده از یک کلاس مشابه، متفاوت هستند.

به عبارتی، این نوع متغیرها مختص اشیاء هستند و مقادیرشان بین اشیاء مختلف کلاس به اشتراک گذاشته نمی‌شوند. به منظور مقداردهی اولیه متغیرهای نمونه، می‌توان از متد__init__()درون کلاس استفاده کرد. زمانی که شی جدیدی را از یک کلاس ایجاد می‌کنید، به‌طور خودکار، متد__init__()فراخوانی می‌شود. بدین ترتیب، می‌توان از این متد برای مقداردهی اولیه مشخصه‌های اشیاء استفاده کرد. در قطعه کد زیر، مثالی از نحوه مقداردهی اولیه متغیرهای نمونه در کلاسPersonملاحظه می‌شود.

1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6object_person = Person('John', 25)
7print(f"I'm {object_person.name}. I'm {object_person.age} years old.")

در مثال بالا، متغیرهایnameوPageمتغیرهای نمونه از کلاسPersonهستند و به هنگام ساخت شیobject_person، تابع__init__()فراخوانی می‌شود و مقادیرJohnو25درون متغیرهای نمونهnameوageقرار می‌گیرند. همان‌طور که در این مثال ملاحظه می‌کنید، نخستین پارامتر تابع__init__()، مقدارselfاست. در زبان برنامه نویسی پایتون، زمانی که با استفاده از نام شی، تابعی (متدی) را فراخوانی می‌کنیم، به‌طور خودکار، خود شی به عنوان اولین پارامتر، به آن تابع ارسال می‌شود.

بنابراین، دستورPerson('John',25)در قطعه کد بالا، معادل دستورPerson(object_person, 'John',25)است. به همین دلیل، اولین پارامتر تابع درون کلاس، باید پارامترselfباشد که به شی فعلی کلاس اشاره دارد. می‌توان نامselfرا تغییر داد، اما به منظور فهم دقیق‌تر کدها و پایبند بودن به قراردادهای زبان پایتون، بهتر است که از همین کلمه کلیدی برای اشاره به شی استفاده شود. خروجی قطعه کد بالا در ادامه ملاحظه می‌شود:

I'm John. I'm 22 years old.

در تصویر زیر نیز مثالی برای متغیرهای نمونه یا همان متغیرهای وهله‌ای در شی گرایی پایتون ارائه شده است.

متغیرهای نمونه در کلاس پایتون

تعریف متدهای کلاس در پایتون

درون کلاس علاوه بر ویژگی، می‌توان توابعی را نیز تعریف کرد که عملیات مختلفی را انجام می‌دهند. به توابع درون کلاس، متد گفته می‌شود.

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

  • «متد وهله‌ای» (Instance Method)
  • «متد کلاس» (Class Method)

در ادامه این مطلب، به توضیح انواع متدهای کلاس پایتون به همراه مثال‌های کاربردی پرداخته شده است.

متد وهله ای در کلاس پایتون چیست ؟

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

اولین آرگومان دریافتی این متدها، عبارتselfاست که به شی اشاره دارد. در ادامه، قطعه کدی ملاحظه می‌شود که نحوه تعریف متد نمونه کلاس را نشان می‌دهد.

1class Request:
2    def send(self):
3        print('Sent')
4
5http_request = Request()
6print(http_request.send()) # Sent

متد کلاس در پایتون

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

متدهای کلاس را می‌توان به دو روش در پایتون ایجاد کرد. در اولین روش، از «دکوراتوری» (Decorator) با نام@classmethodاستفاده می‌شود که در ادامه قطعه کدی از کاربرد این دکوراتور در ساخت متد کلاس ارائه شده است.

1from datetime import date
2
3class Student:
4    def __init__(self, name, age):
5        self.name = name
6        self.age = age
7
8    @classmethod
9    def calculate_age(cls, name, birth_year):
10        # calculate age an set it as a age
11        # return new object
12        return cls(name, date.today().year - birth_year)
13
14    def show(self):
15        print(self.name + "'s age is: " + str(self.age))
16
17
18# create new object using the factory method
19joy = Student.calculate_age("Joy", 1995)
20joy.show()

در مثال بالا، متدcalculate_ageاز نوع متد کلاس است. خاطر نشان می‌شود نخستین پارامتر متد کلاس باید مقدارclsباشد که به نام کلاس جاری اشاره می‌کند.

متد کلاس در پایتون

روش دیگری که با کمک آن می‌توان متد کلاس تعریف کرد، استفاده از تابعclassmethodاست. به هنگام استفاده از این تابع، باید متدی را درون کلاس تعریف کرد و نام متد را به عنوان آرگومان تابعclassmethodدر نظر گرفت تا این تابع، متد مشخص شده را به متد کلاس تبدیل کند. در قطعه کد زیر، مثالی از کاربرد تابعclassmethodبرای ساخت متد کلاسschool_nameملاحظه می‌شود.

1class School:
2    # class variable
3    name = 'ABC School'
4
5    def school_name(cls):
6        print('School Name is :', cls.name)
7
8# create class method
9School.school_name = classmethod(School.school_name)
10
11# call class method
12School.school_name()

اصول شی گرایی در پایتون

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

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

  • اصل «کپسوله‌سازی» (Encapsulation)
  • اصل «انتزاع | تجرید» (Abstraction)
  • «وراثت | ارث‌بری» (Inheritance)
  • «پلی مورفیسم | چندریختی» (Polymorphism)

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

اصل وراثت شی گرایی در پایتون چیست ؟

یکی از اصول شی گرایی در پایتون، اصل وراثت یا ارث‌بری است که در طی این فرآیند، می‌توان کلاسی را ایجاد کرد که ویژگی‌ها و متدهای خود را از کلاس دیگری به ارث ببرد که از قبل تعریف شده است. در این حال، کلاس جدید، کلاس فرزند (Child Class) نام دارد و به کلاسی که مشخصه‌های خود را به کلاس فرزند می‌دهد، کلاس والد (Parent Class) گفته می‌شود.

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

ممکن است فرزند رنگ موی خود را از مادرش به ارث ببرد. با این حال، فرزند تصمیم می‌گیرد رنگ موی خود را تغییر دهد و موی خود را به رنگ صورتی تغییر دهد. با اینکه فرزند، داشتن ویژگی رنگ مو را از پدر و مادر خود به ارث برده است، اما می‌تواند به تصمیم خود، رنگ آن را تغییر دهد و موی خود را به رنگی درآورد که مشابه رنگ موی پدر و مادر خود نیست.

اصل وراثت در شی گرایی در پایتون چیست

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

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

1class Person:
2    def __init__(self, name):
3        self.name = name
4
5    def greet(self):
6        return f"Hi, it's {self.name}"

حال می‌خواهیم کلاسی با نامEmployeeایجاد کنیم که دقیقاً مشخصه‌های کلاسPersonرا داشته باشد. در قطعه کد زیر، نحوه ساخت کلاسPersonملاحظه می‌شود.

1class Employee:
2    def __init__(self, name, job_title):
3        self.name = name
4        self.job_title = job_title
5
6    def greet(self):
7        return f"Hi, it's {self.name}"

همان‌طور که در قطعه آمده است، کلاسEmployeeدارای متدgreetاست که همین متد در کلاسPersonنیز وجود دارد. با استفاده از اصل وراثت در شی گرایی پایتون، می‌توان متدgreetرا از کلاسEmployeeحذف کرد و با ایجاد ارتباط بین دو کلاسEmployeeوPerson، متدgreetرا از کلاسPersonبه ارث برد. در این حالت، کلاسEmployeeبه عنوان کلاس فرزند و کلاسPersonبه عنوان کلاس والد مشخص می‌شوند. در ادامه، نحوه به‌کارگیری اصل وراثت در پایتون ملاحظه می‌شود.

1class Employee(Person):
2    def __init__(self, name, job_title):
3        self.name = name
4        self.job_title = job_title

همان‌طور که در قطعه کد بالا دیده می‌شود، می‌توان در خط اعلان کلاس فرزند، نام کلاس والد را در داخل پرانتز قرار داد. بدین ترتیب، کلاسEmployeeعلاوه بر ویژگی‌هایnameوjob_title، دارای متدgreetنیز هست که آن را از کلاس والد خود، یعنی کلاسPerson، به ارث می‌برد. در ادامه، مثالی از نحوه دسترسی به متدgreetاز طریق شی ساخته شده از کلاسEmployeeملاحظه می‌شود.

1employee = Employee('John', 'Python Developer')
2print(employee.greet())

خروجی قطعه کد بالا در ادامه نشان داده شده است:

Hi, it's John

با استفاده از تابعissubclass()می‌توان مشخص کرد که آیا دو کلاس رابطه والد - فرزندی دارند؟ در ادامه، نحوه استفاده از این تابع در زبان پایتون در قالب مثال، نشان داده شده است:

1print(issubclass(Employee, Person)) # True

همچنین، با استفاده ازsuper()می‌توان از داخل کلاس فرزند، به متدهای کلاس والد دسترسی داست. در ادامه، قطعه کدی از زبان پایتون ارائه شده است که نحوه استفاده ازsuper()را نشان می‌دهد.

1class Employee:
2    def __init__(self, name, base_pay, bonus):
3        self.name = name
4        self.base_pay = base_pay
5        self.bonus = bonus
6
7    def get_pay(self):
8        return self.base_pay + self.bonus
9
10
11class SalesEmployee(Employee):
12    def __init__(self, name, base_pay, bonus, sales_incentive):
13        super().__init__(name, base_pay, bonus)
14        self.sales_incentive = sales_incentive
15
16    def get_pay(self):
17        return super().get_pay() + self.sales_incentive
18
19
20if __name__ == '__main__':
21    sales_employee = SalesEmployee('John', 5000, 1000, 2000)
22    print(sales_employee.get_pay())  # 8000

اصل وراثت می‌تواند از راه‌های مختلف در برنامه نویسی استفاده شود. به عبارتی، انواع مختلفی از ارث‌بری در شی گرایی وجود دارد که در ادامه به آن‌ها اشاره شده است.

  • «وراثت منفرد» (Single Inheritance)
  • «وراثت چندگانه» (Multiple Inheritance)
  • «وراثت چند سطحی» (Multi-Level Inheritance)
  • «وراثت سلسله‌مراتبی» (Hierarchical Inheritance)
  • «وراثت ترکیبی» (Hybrid Inheritance)
انواع ارث بری در شی گرایی در پایتون چیست
انواع ارث بری در شی گرایی

در ادامه مطلب حاضر، به توضیح هر یک از انواع وراثت پرداخته می‌شود و مثالی کاربردی از زبان پایتون برای هر یک از آن‌ها ارائه خواهد شد.

وراثت منفرد در پایتون

یکی از انواع نحوه ارث‌بری در شی گرایی، نوع ارث‌بری منفرد است. در این نوع وراثت، هر کلاس فرزند تنها دارای یک کلاس والد است و تمامی ویژگی‌ها و متدهای کلاس والد را به ارث می‌برد. در مثال زیر، نحوه ارث‌بری کلاس فرزند از یک کلاس والد در پایتون ملاحظه می‌شود.

1#syntax_of_single_inheritance
2
3class class1:               #parent_class
4    pass
5
6class class2(class1):       #child_class
7    pass
8
9obj_name = class2()
نوع ارث‌بری مثالی که در بخش پیشین درباره دو کلاسEmployeeوPerson ارائه شد، از نوع وراثت منفرد است.

وراثت چندگانه شی گرایی در پایتون چیست ؟

زمانی که چندین کلاس وجود داشته باشند و بخواهیم کلاس جدیدی را به عنوان کلاس فرزند ایجاد کنیم که تمامی مشخصه‌های کلاس‌های موجود را به ارث ببرد، از وراثت چندگانه استفاده می‌کنیم.

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

1#syntax_of_multiple_inheritance
2
3class parent_1:
4    pass
5
6class parent_2:
7    pass
8
9class child(parent_1,parent_2):
10    pass
11
12obj = child()

مثال زیر نیز، قطعه کدی از زبان پایتون را نشان می‌دهد که در آن دو کلاس والد با نام‌هایBrandsوProductsساخته شده‌اند و کلاس فرزندی نیز با نامPopularityتعریف شده است که از دو کلاس والد ارث‌بری می‌کند.

1#example_of_multiple_inheritance
2
3class Brands:               #parent_class
4    brand_name_1 = "Amazon"
5    brand_name_2 = "Ebay"
6    brand_name_3 = "OLX"
7    
8class Products:            #child_class
9    prod_1 = "Online Ecommerce Store"
10    prod_2 = "Online Store"
11    prod_3 = "Online Buy Sell Store"
12
13class Popularity(Brands,Products):
14    prod_1_popularity = 100
15    prod_2_popularity = 70
16    prod_3_popularity = 60
17    
18obj_1 = Popularity()          #Object_creation
19print(obj_1.brand_name_1+" is an "+obj_1.prod_1))
20print(obj_1.brand_name_2+" is an "+obj_1.prod_2))
21print(obj_1.brand_name_3+" is an "+obj_1.prod_3))

خروجی قطعه کد بالا، در ادامه ملاحظه می‌شود.

#Output
#Amazon is an Online Ecommerce Store popularity of 100
#Ebay is an Online Store popularity of 70
#OLX is an Online Buy Sell Store popularity of 60

وراثت چندسطحی در شی گرایی در پایتون چیست ؟

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

1#Syntax_of_multilevel_inheritance
2
3class A:
4    pass
5
6class B(A):
7    pass
8
9class C(B):
10    pass
11
12obj = C()

مثال زیر، نمونه‌ای از نحوه پیاده‌سازی اصل وراثت از نوع چندسطحی را در پایتون نشان می‌دهد. در این مثال، کلاسProdustsبه عنوان کلاس والد برای کلاسPopularityتعریف شده است که خودش به عنوان کلاس فرزند برای کلاسBrandsمحسوب می‌شود. بدین ترتیب، کلاسPopularityاز مشخصه‌های کلاس‌هایProductsوBrandsارث‌بری می‌کند.

1class Brands:                      #parent_class
2    brand_name_1 = "Amazon"
3    brand_name_2 = "Ebay"
4    brand_name_3 = "OLX"
5    
6class Products(Brands):            #child_class
7    prod_1 = "Online Ecommerce Store"
8    prod_2 = "Online Store"
9    prod_3 = "Online Buy Sell Store"
10
11class Popularity(Products):        #grand_child_class
12    prod_1_popularity = 100
13    prod_2_popularity = 70
14    prod_3_popularity = 60
15    
16    
17obj_1 = Popularity()          #Object_creation
18print(obj_1.brand_name_1+" is an "+obj_1.prod_1+" popularity of "+str(obj_1.prod_1_popularity))
19print(obj_1.brand_name_2+" is an "+obj_1.prod_2+" popularity of "+str(obj_1.prod_2_popularity))
20print(obj_1.brand_name_3+" is an "+obj_1.prod_3+" popularity of "+str(obj_1.prod_3_popularity))
21
22#Output
23#Amazon is an Online Ecommerce Store popularity of 100
24#Ebay is an Online Store popularity of 70
25#OLX is an Online Buy Sell Store popularity of 60

وراثت سلسله مراتبی شی گرایی در پایتون چیست ؟

وراثت سلسله مراتبی این امکان را فراهم می‌کند تا یک کلاس والد تعریف کنیم و کلاس‌های فرزند مختلفی بسازیم که از آن کلاس والد ارث‌بری می‌کنند. ساختار نحوی این نوع وراثت در زبان پایتون به شکل زیر است:

1#syntax_of_hierarchical_inheritance
2
3class A:                  #parent_class
4    pass
5    
6class B(A):               #child_class
7    pass
8
9class C(A):               #child_class
10    pass
11
12class D(A):               #child_class
13    pass
14
15obj_1 = B()       #Object_creation
16obj_2 = C()
17obj_3 = D()

در مثال زیر، نمونه‌ای از وراثت سلسله مراتبی در پایتون ملاحظه می‌شود. در این مثال، کلاس‌های فرزندPopularity،ValueوProductsاز تنها کلاس والدBrandsارث‌بری می‌کنند.

1#example
2
3class Brands:                      #parent_class
4    brand_name_1 = "Amazon"
5    brand_name_2 = "Ebay"
6    brand_name_3 = "OLX"
7    
8class Products(Brands):            #child_class
9    prod_1 = "Online Ecommerce Store"
10    prod_2 = "Online Store"
11    prod_3 = "Online Buy Sell Store"
12
13class Popularity(Brands):        #grand_child_class
14    prod_1_popularity = 100
15    prod_2_popularity = 70
16    prod_3_popularity = 60
17
18class Value(Brands):
19    prod_1_value = "Excellent Value"
20    prod_2_value = "Better Value"
21    prod_3_value = "Good Value"
22    
23obj_1 = Products()          #Object_creation
24obj_2 = Popularity()
25obj_3 = Value()
26print(obj_1.brand_name_1+" is an "+obj_1.prod_1)
27print(obj_1.brand_name_1+" is an "+obj_1.prod_1)
28print(obj_1.brand_name_1+" is an "+obj_1.prod_1)

خروجی قطعه کد بالا در ادامه نشان داده شده است:

#Output
#Amazon is an Online Ecommerce Store
#Ebay is an Online Store
#OLX is an Online Buy Sell Store

وراثت ترکیبی در پایتون

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

نمونه‌ای از ساختار نحوی پایتون را برای تعریف وراثت ترکیبی در ادامه ملاحظه می‌کنید.

1#Syntax_Hybrid_inheritance
2
3class PC: 
4	pass
5	
6class Laptop(PC): 
7	pass
8	
9class Mouse(Laptop): 
10	pass
11	
12class Student3(Mouse, Laptop): 
13	pass
14	
15# Driver's code 
16obj = Student3()

در ادامه نیز، قطعه کدی از زبان پایتون ارائه شده است که مثالی از وراثت ترکیبی را نشان می‌دهد.

1#Example_Hybrid_inheritance
2class PC:
3def fun1(self):
4print(“This is PC class)
5
6class Laptop(PC):
7def fun2(self):
8print(“This is Laptop class inheriting PC class)
9
10class Mouse(Laptop):
11def fun3(self):
12print(“This is Mouse class inheriting Laptop class)
13
14class Student(Mouse, Laptop):
15def fun4(self):
16print(“This is Student class inheriting PC and Laptop”)
17
18# Driver’s code
19obj = Student()
20obj1 = Mouse()
21obj.fun4()
22obj.fun3()

اصل کپسوله سازی شی گرایی در پایتون چیست ؟

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

به عبارتی، تمامی ویژگی‌ها و متدهای یک ماهیت، در یک کلاس تعریف می‌شوند و می‌توان مشخص کرد که با تعریف شی به کدام یک از این مشخصه‌ها می‌توان دسترسی داشت. بر اساس اصل کپسوله‌سازی شی گرایی، می‌توان سه نوع سطح دسترسی به مشخصه‌های درون کلاس اختصاص داد که در ادامه به آن‌ها اشاره شده است:

  • مشخصه‌هایی از نوع «عمومی» (Public)
  • مشخصه‌هایی از نوع «خصوصی» (Private)
  • مشخصه‌هایی از نوع «محافظت شده» (Protected)
کپسوله سازی در شی گرایی پایتون چیست

در ادامه، به توضیح هر یک از انواع سطوح دسترسی به مشخصه‌های کلاس پرداخته می‌شود.

مشخصه های عمومی کلاس در پایتون

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

در قطعه کد زیر، مثالی از مشخصه‌های عمومی کلاس در زبان پایتون ارائه شده است. در این مثال، ویژگی‌هایnameوageو متدprint_nameبه عنوان مشخصه‌های عمومی کلاسPersonمحسوب می‌شوند که با استفاده از شیobject_personمی‌توان از خارج کلاس، به آن‌ها دسترسی داشت.

1class Person: 
2    def __init__(self, name, age): 
3        self.name = name 
4        self.age = age 
5    def print_name(self):
6        print('The name is :' , self.name)
7
8object_person = Person('John', 25)
9print(object_person.name)
10object_person.print_name()

مشخصه های محافظت شده کلاس در پایتون

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

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

در قطعه کد زیر، مثالی از نحوه کاربرد ویژگی‌های محافظت شده در پایتون ارائه شده است. در این مثال، متغیر_qاز نوع متغیر محافظت شده است که نام آن با علامت (_) آغاز می‌شود.

1class Base1:  
2    def __init__(self):  
3          self._q = "Javatpoint"  
4
5obj_1 = Base1()  
6print(obj_1._q)  

خروجی قطعه کد بالا، در ادامه آمده است.

Javatpoint

به منظور تعریف متدهای محافظت شده درون کلاس نیز می‌توان قبل از نام متد، از علامت_در پایتون استفاده کرد. در قطعه کد زیر، مثالی از نحوه تعریف متد محافظت شده در زبان پایتون ارائه شده است. همان‌طور که در این مثال ملاحظه می‌شود، متد_warmupاز نوع متد محافظت شده به حساب می‌آید.

1class Person:
2    def __init__(self, name):
3        self.name = name
4    def _warmup(self):
5        print("{} is warming up".format(self.name))
6jack = Person ('Jack')
7jack._warmup()

خروجی قطعه کد بالا در ادامه ملاحظه می‌شود.

Jack is warming up

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

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

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

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

1class Base1: 
2    def __init__(self): 
3        self.__q = "Javatpoint" 
4
5obj_1 = Base1() 
6print(obj_1.__q)

خروجی قطعه کد بالا، در ادامه ملاحظه می‌شود.

Javatpoint

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

1class Person: 
2    def __init__(self, name): 
3        self.name = name 
4    def __warmup(self): 
5        print("{} is warming up".format(self.name))
6jack = Person ('Jack')
7jack.__warmup()

خروجی قطعه کد بالا در ادامه ملاحظه می‌شود.

Jack is warming up

اصل انتزاع شی گرایی در پایتون

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

به عبارتی، باید کلاس‌های فرزندی را ایجاد کرد که از کلاس‌های انتزاعی ارث‌بری می‌کنند و سپس با تعریف اشیای جدید از کلاس‌های فرزند، بتوان به متدهای کلاس‌های انتزاعی دسترسی داشت. کلاس انتزاعی شامل «متدهای انتزاعی» (Abstract Method) می‌شود.

متدهای انتزاعی، متدهایی هستند که صرفاً اعلان شده‌اند اما بدنه آن‌ها تعریف نشده است. کلاس‌های انتزاعی زمانی کاربرد دارند که بخواهیم کلاس‌های مختلفی ایجاد کنیم که دارای متدهایی با نام‌های یکسان باشند،‌ اما با استفاده از روش «بازنویسی متد» (Method Overriding)، دستورات متفاوتی را برای این متدها در کلاس‌های فرزند تعریف کنیم.

انتزاع در پایتون

بر خلاف کلاس‌های عادی در پایتون، برای تعریف کلاس انتزاعی باید از کتابخانه  استفاده کرد. به عبارتی،‌ به‌طور مستقیم نمی‌توان کلاس انتزاعی را در زبان پایتون تعریف کرد و باید از کتابخانه‌ای با نامabcاستفاده شود. در این کتابخانه، ماژولی با نامABCوجود دارد که باید برای تعریف کلاس انتزاعی در پایتون فراخوانی شود. برای ساخت متد انتزاعی در پایتون نیز پیش از خط اعلان متد، از دستورabc.abstractmethodاستفاده می‌شود.

در قطعه کد زیر، مثالی از نحوه تعریف کلاس انتزاعی در زبان پایتون ارائه شده است. در این مثال، کلاسAbstractClassNameاز نوع کلاس انتزاعی است که ماژولABCدر خط اعلان این کلاس صدا زده می‌شود. متدabstract_method_nameنیز متد انتزاعی کلاس است که با استفاده از دکوراتور@abstractmethodبه عنوان متد انتزاعی در نظر گرفته می‌شود.

1from abc import ABC, abstractmethod
2
3
4class AbstractClassName(ABC):
5    @abstractmethod
6    def abstract_method_name(self):
7        pass

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

 

در قطعه کد زیر، مثالی کاربردی از کلاس انتزاعی و نحوه ارث‌بری از آن ارائه شده است. در این مثال، کلاسEmployee، کلاس انتزاعی است که یک متد انتزاعی با نامget_salaryدارد. کلاس‌هایFulltimeEmployeeوHuprlyEmployeeکلاس‌های فرزند هستند که با روش بازنویسی متد، بدنه متدget_salaryدر این کلاس‌ها با دستورات متفاوت تکمیل شده است.

1from abc import ABC, abstractmethod
2
3
4class Employee(ABC):
5    def __init__(self, first_name, last_name):
6        self.first_name = first_name
7        self.last_name = last_name
8
9    @abstractmethod
10    def get_salary(self):
11        pass
12
13class FulltimeEmployee(Employee):
14    def __init__(self, first_name, last_name, salary):
15        super().__init__(first_name, last_name)
16        self.salary = salary
17
18    def get_salary(self):
19        return self.salary
20
21
22class HourlyEmployee(Employee):
23    def __init__(self, first_name, last_name, worked_hours, rate):
24        super().__init__(first_name, last_name)
25        self.worked_hours = worked_hours
26        self.rate = rate
27
28    def get_salary(self):
29        return self.worked_hours * self.rate

اصل چندریختی در پایتون

اصل «چندریختی | پلی مورفیسم» (Polymorphism) یکی دیگر از اصول مهم شی‌گرایی است و به وضعیتی اطلاق می‌شود که ماهیتی نظیر متد، «عملگر» (Operator) یا شی در شرایط مختلف، رفتار متفاوتی داشته باشند.

اصل چندریختی در پایتون با دو مفهوم «بازنویسی متد» (Method Overriding) و «سربارگذاری متد» (Method Overloading) سر و کار دارد. در بخش مربوط به اصل انتزاع به توضیح مفهوم بازنویسی متد پرداخته شد. از این روش در مواقعی استفاده می‌شود که در کلاس فرزند، متدی هم‌نام با متد کلاس والد ایجاد شود، به طوری که این متد شامل دستوراتی مغایر با دستورات متد کلاس والد باشد. به عبارتی، می‌توان گفت با اصل چندریختی، یک متد در کلاس‌های مختلف (در کلاس‌های فرزند) عملکرد متفاوتی دارد.

اصل چند ریختی در پایتون

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

1class Example:
2    def multiply(self,a,b,c=1):
3        print(a*b*c)
4
5example = Example()
6example.multiply(5,10)
7example.multiply(2,5,6)

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

 

مدیریت ویژگی در کلاس های پایتون

گاهی لازم است برای دسترسی به ویژگی‌هایی که در کلاس وجود دارند، محدودیت‌هایی را لحاظ کنیم. به عنوان مثال، چنانچه کلاسی برای ماهیت Person تعریف کرده باشیم که دارای ویژگی‌های مختلفی نظیر اسم و سن باشد، می‌توان برای ویژگی سن، محدودیتی لحاظ کرد تا کاربر، این ویژگی را با مقادیر منفی مقداردهی نکند.

برای اعمال محدودیت بر روی ویژگی‌های کلاس، می‌توان از دو متد getter و setter در داخل کلاس استفاده کرد. به منظور درک بهتر مطلب حاضر، بهتر است مثالی در این باره ارائه کنیم. قطعه کد زیر را در نظر بگیرید که کلاسی را با نامPersonبا ویژگی‌هایnameوageتعریف می‌کند.

1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6
7john = Person('John', 18)

از آنجایی کهageبه عنوان ویژگی نمونه تعریف شده است، می‌توان در ادامه برنامه، مقادیر آن را تغییر داد:

1john.age = 19
2...
3...
4...
5john.age = -1

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

1age = -1
2if age <= 0:
3    raise ValueError('The age must be positive')
4else:
5    john.age = age

با این حال، این روش باعث افزایش تعداد کدهای تکراری برنامه می‌شود و چنین راه‌حلی بهینه نیست. به جای استفاده از این روش، می‌توان از دو متد getter و setter در داخل کلاس استفاده کرد تا بر روی اعمال تغییرات در مقادیر ویژگی‌ها نظارتی انجام شود. به عبارتی، متدهای getter و setter به عنوان رابطی برای دسترسی به ویژگی‌های نمونه کلاس در پایتون محسوب می‌شوند. وظیفه این دو متد به شرح زیر است:

  • متد getter مقدار ویژگی‌ نمونه را در خروجی بازمی‌گرداند.
  • متد setter مقدار جدیدی را برای ویژگی نمونه لحاظ می‌کند.

در قطعه کد زیر، مثالی از نحوه تعریف متدهای getter و setter برای ویژگیageارائه شده است. خاطر نشان می‌شود به منظور استفاده از متدهای getter و setter بر اساس قرارداد، نوع ویژگیageرا که از نوع عمومی است،‌ به نوع محافظت شده (یعنی_age) تبدیل می‌کنیم.

1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.set_age(age)
5
6    def set_age(self, age):
7        if age <= 0:
8            raise ValueError('The age must be positive')
9        self._age = age
10
11    def get_age(self):
12        return self._age

بر اساس قطعه کد ارائه شده، متدset_age()به عنوان متد setter و متدget_age()به عنوان متد getter محسوب می‌شوند. در متدset_age()مقدار ویژگیageبررسی می‌شود که اگر مقدار آن کم‌تر از عدد صفر باشد، خطایی به کاربر در خروجی نشان بدهد مبنی بر این که مقدار عددی ورودی برای ویژگی سن باید عددی مثبت باشد. متدget_age()نیز مقدار ویژگیageرا در خروجی بازمی‌گرداند. در متد__init__()نیز متدset_age()را برای مقداردهی ویژگیageفراخوانی می‌کنیم. بدین ترتیب، چنانچه مقداری منفی را برای ویژگی لحاظ کنیم، با اجرای برنامه با خطای زیر در خروجی مواجه می‌شویم:

ValueError: The age must be positive

 

تغییراتی که در کلاسPersonتا به اینجا اعمال کردیم، به درستی کار می‌کنند. با این حال، چنانچه از قبل، در حال توسعه پروژه نرم‌افزاری بوده باشید و قطعه کدهای خود را بر اساس کلاس به گونه‌ای نوشته باشید که تغییرات جدید مربوط به متدهای setter و getter را پشتیبانی نکنند، باید تمامی قسمت‌های برنامه خود را تغییر بدهید تا با نسخه جدید کلاسPersonمطابقت پیدا کنند.

البته شی گرایی در پایتون راه‌حل بهتری را برای رفع مشکل مطرح شده ارائه می‌دهد. چنانچه بخواهید متدهای getter و setter را در کلاس تعریف کنید، بهتر است که از تابعProperty استفاده کنید. این کلاس، دارای چندین آرگومان ورودی است که در ادامه به آن‌ها اشاره شده است:

  • آرگومانfget: نام متد getter را مشخص می‌کند.
  • fset: نام متد setter را مشخص می‌کند.
  • آرگومانfdel: نام متدی است که مشخصه مورد نظر را حذف می‌کند.

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

1class Person:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6    def set_age(self, age):
7        if age <= 0:
8            raise ValueError('The age must be positive')
9        self._age = age
10
11    def get_age(self):
12        return self._age
13
14    age = property(fget=get_age, fset=set_age)
15
16john = Person ('John', 18)
17john.age = 19

چنانچه مقدار ویژگیageرا با استفاده از شیjohnاز خارج کلاس تغییر دهید، پایتون متدset_age()را از طریق آرگومانfsetفراخوانی می‌کند و مقدار ویژگیageرا تغییر می‌دهد. به منظور نمایش مقدار ویژگیageدر خروجی با استفاده از شیٔ در خارج از کلاس، می‌توان از دستور زیر استفاده کرد:

1print(john.age)

علاوه بر روش بالا، می‌توان مستقیماً متدget_age()را با استفاده از شی به صورت زیر فراخوانی کرد:

1print(john.get_age())

تمرین برنامه نویسی شی گرا با زبان پایتون

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

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

تمرین ۱. تعریف کلاس در پایتون

با استفاده از پایتون، کلاسی با نامVehicleایجاد کنید که هیچ گونه مشخصه‌ای نداشته باشد.

پاسخ تمرین ۱

پاسخ این تمرین به صورت زیر است:

1class Vehicle:
2    pass

تمرین ۲. تعریف مشخصه های کلاس و شی در پایتون

با استفاده از زبان برنامه نویسی پایتون، کلاسی با نامVehicleرا ایجاد کنید که دارای دو متغیر نمونه با نام‌هایmax_speedوmileageباشد. سپس شیئ از این کلاس ایجاد کنید که با استفاده از آن، دو متغیر نمونه، با مقادیر دلخواه مقداردهی شوند. در نهایت، مقادیر متغیرهای نمونه را با استفاده از شی تعریف شده، در خروجی چاپ کنید.

پاسخ تمرین ۲

جواب تمرین ۲ در ادامه آمده است.

1class Vehicle:
2    def __init__(self, max_speed, mileage):
3        self.max_speed = max_speed
4        self.mileage = mileage
5
6modelX = Vehicle(240, 18)
7print(modelX.max_speed, modelX.mileage)

تمرین ۳. ارث بری در پایتون

با زبان پایتون قطعه کدی بنویسید که کلاس فرزندی را با نامBusایجاد کند که تمامی مشخصه‌های خود را از کلاس والدVehicleبه ارث می‌برد. مشخصه‌های کلاس والد می‌توانند شامل متغیرهای نمونهname،max_speedوmileageباشند. سپس مشخصه‌های کلاس فرزند را با مقادیر دلخواه مقداردهی کنید و در نهایت مقادیر آن‌ها را در خروجی نشان دهید.

پاسخ تمرین ۳

پاسخ این تمرین در ادامه مشاهده می‌شود.

1class Vehicle:
2
3    def __init__(self, name, max_speed, mileage):
4        self.name = name
5        self.max_speed = max_speed
6        self.mileage = mileage
7
8class Bus(Vehicle):
9    pass
10
11School_bus = Bus("School Volvo", 180, 12)
12print("Vehicle Name:", School_bus.name, "Speed:", School_bus.max_speed, "Mileage:", School_bus.mileage)

تمرین ۴. باز نویسی متد در کلاس پایتون

با زبان پایتون برنامه‌ای بنویسید که کلاس فرزندی را با نامBusایجاد کند که تمامی مشخصه‌های خود را از کلاس والدVehicleبه ارث می‌برد.

مشخصه‌های کلاس والد می‌توانند شامل متغیرهای نمونهname،max_speedوmileageباشند. همچنین، در کلاس والد، متدی با نامseating_capacityرا تعریف کنید که پارامتری با نامseating_capacityدریافت کند. متدseating_capacityرا در کلاس فرزند با استفاده از بازنویسی متد به نحوی تغییر دهید که مقدار پیش‌فرض ۵۰ برای پارامتر این تابع در نظر گرفته شود.

پاسخ تمرین ۴

پاسخ تمرین ۴ به صورت زیر است.

1class Vehicle:
2    def __init__(self, name, max_speed, mileage):
3        self.name = name
4        self.max_speed = max_speed
5        self.mileage = mileage
6
7    def seating_capacity(self, capacity):
8        return f"The seating capacity of a {self.name} is {capacity} passengers"
9
10class Bus(Vehicle):
11    # assign default value to capacity
12    def seating_capacity(self, capacity=50):
13        return super().seating_capacity(capacity=50)
14
15School_bus = Bus("School Volvo", 180, 12)
16print(School_bus.seating_capacity())

تمرین ۵. متغیرهای کلاس در پایتون

با استفاده از زبان برنامه نویسی پایتون قطعه کدی برای ساخت کلاس والد با نامVehicleبنویسید که علاوه بر متغیرهای نمونهname،max_speedوmileage، متغیر کلاسی با نامColorنیز داشته باشد تا مقدار این متغیر برای تمامی اشیای ساخته شده از کلاس والد و تمامی کلاس‌های فرزند آن به اشتراک گذاشته شود.

کلاس‌های فرزندی با نام‌هایBusوCarنیز ایجاد کنید که از کلاسVehicleارث‌بری می‌کنند. برای هر یک از این کلاس‌های فرزند، شیئی بسازید و مقادیری برای متغیرهای نمونه آن‌ها تعریف کنید. در نهایت، مقادیر تمامی مشخصه‌های اشیاء را در خروجی نشان دهید.

پاسخ تمرین ۵

پاسخ این تمرین در ادامه آمده است.

1class Vehicle:
2    # Class attribute
3    color = "White"
4
5    def __init__(self, name, max_speed, mileage):
6        self.name = name
7        self.max_speed = max_speed
8        self.mileage = mileage
9
10class Bus(Vehicle):
11    pass
12
13class Car(Vehicle):
14    pass
15
16School_bus = Bus("School Volvo", 180, 12)
17print(School_bus.color, School_bus.name, "Speed:", School_bus.max_speed, "Mileage:", School_bus.mileage)
18
19car = Car("Audi Q5", 240, 18)
20print(car.color, car.name, "Speed:", car.max_speed, "Mileage:", car.mileage)

تمرین ۶. بررسی رابطه والد و فرزندی بین کلاس ها

کلاس والدی با نامVehicleو کلاس فرزندی با نامBusایجاد کنید و درنهایت مشخص کنید آیا کلاسBusبه عنوان کلاس فرزند برای کلاسVehicleمحسوب می‌شود یا خیر؟

پاسخ تمرین ۶

جواب تمرین ۶ در ادامه ارائه شده است.

1class Vehicle:
2    def __init__(self, name, mileage, capacity):
3        self.name = name
4        self.mileage = mileage
5        self.capacity = capacity
6
7class Bus(Vehicle):
8    pass
9
10School_bus = Bus("School Volvo", 12, 50)
11
12# Python's built-in isinstance() function
13print(isinstance(School_bus, Vehicle))

جمع‌بندی

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

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

بر اساس رای ۲۱ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
Real PythonPython TutorialjavaTpointPYnative
۴ دیدگاه برای «شی گرایی در پایتون چیست؟ – به زبان ساده + مثال و تمرین»

هشت غلط املایی فقط با وحله بجای وهله!

با سلام؛

متن بازبینی و مجدد اصلاح شد. از بازخورد شما سپاس‌گزاریم.

با تشکر از همراهی شما با مجله فرادرس

عالی و جامع بود. دستتون درد نکنه.

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *