«شی گرایی» یا «برنامه نویسی شی گرا» (Object-Oriented Programming | OOP) یکی از رویکردهای مهم در برنامه نویسی است که بسیاری از برنامهنویسان با استفاده از این رویکرد به توسعه پروژههای خود میپردازند. این شیوه شامل مفاهیم کلیدی و اصول خاصی میشود که باید از آنها در پیادهسازی برنامههای مبتنی بر این روش استفاده شود. زبان برنامه نویسی پایتون از جمله محبوبترین و پرکاربردترین زبانهای برنامه نویسی به حساب میآید که شیگرا هم هست و به خوبی میتوان اصول شیگرایی را در آن پیادهسازی کرد. بنابراین در مطلب حاضر، سعی بر این است به شی گرایی در پایتون بپردازیم و مثالهای کاربردی را از این زبان ارائه کنیم تا مخاطبان با رویکرد برنامه نویسی شی گرا در پایتون آشنا شوند.
شی گرایی در پایتون چیست ؟
رویکرد برنامه نویسی شی گرا، بر پایه دو مفهوم اصلی «شی» (Object) و «کلاس» (Class) شکل گرفته است که با این دو مفهوم میتوان اطلاعات تمام «ماهیتهای» (Entity) دنیای واقعی را در برنامه به راحتی ذخیره کرد.
به بیان جزئیتر میتوان گفت هدف از شی گرایی در پایتون ساخت کلاسی است که دربرگیرنده تمامی «ویژگیها» (Properties) و «رفتارها | متدهای» (Methods) مرتبط با یک ماهیت باشد و از طریق ایجاد شی از کلاس مربوطه بتوان به همه «مشخصهها» (Attributes) یا همان ویژگیها و متدها دسترسی داشت.
به عنوان مثال، میتوان ماهیت یک شخص را در دنیای واقعی در نظر گرفت که این ماهیت شامل مجموعهای از ویژگیها و رفتارهای (متدهای) مختلفی نظیر نام، سن، آدرس محل سکونت، راه رفتن، صحبت کردن و دویدن میشود. در برنامه نویسی شی گرا با استفاده از ساخت کلاس میتوان این مشخصهها را تعریف کرد و قالبی را به وجود آورد و سپس برای تعریف افراد مختلف با اطلاعات متفاوت، اشیای مختلفی را از این کلاس ایجاد کرد.
شی گرایی علاوه بر مفاهیم شی و کلاس دارای اصول مهمی هم هست که پیادهسازی برنامههای مبتنی بر شی گرایی باید با درک و شناخت این اصول انجام شود. در ادامه مطلب، به توضیح جزئیتری از مفاهیم و اصول شی گرایی خواهیم پرداخت و مثالهای کاربردی از زبان برنامه نویسی پایتون برای هر یک از آنها ارائه خواهد شد.
شی و کلاس در پایتون
انواع دادههای پایتون نظیر اعداد، رشتهها و لیستها به منظور ذخیره مقادیر سادهای از اطلاعات ایجاد شدهاند. به عنوان مثال، با تعریف متغیرهایی با نامهای Price و ColorName از نوع عددی و رشتهای، میتوان به ترتیب، قیمت یک سیب و رنگ آن را ذخیره کرد.
حال فرض کنید قصد دارید با اطلاعات پیچیدهتری در برنامه نویسی کار کنید. به عنوان مثال، مدیر شرکت از شما میخواهد اطلاعات شخصی کارمندان را در یک فایل ذخیره کنید. این اطلاعات میتواند شامل نام کارمندان، سن، سِمَت شغلی و تاریخ شروع به کار آنها باشد.
یکی از روشهای ذخیرهسازی چنین اطلاعاتی در زبان پایتون این است که از ساختار داده لیست استفاده شود و برای هر کارمند در سازمان، لیستی از اطلاعات شخصی بسازید. مثال زیر، اطلاعات سه کارمند را نشان میدهد که با استفاده از ساختار داده لیست در سه متغیر جداگانه ذخیره شدهاند:
kirk = ["James Kirk", 34, "Captain", 2265]
spock = ["Spock", 35, "Science Officer", 2254]
mccoy = ["Leonard McCoy", "Chief Medical Officer", 2266]
با این که چنین روشی برای ذخیره اطلاعات کارمندان، ساده است، اما مشکلات مهمی دارد. چنانچه بخواهید به اطلاعات هر شخص در برنامه دسترسی داشته باشید، باید از اندیس استفاده شود. به عنوان مثال، اندیس صفر از لیست kirk
، نام کارمند را مشخص میکند.
زمانی که قطعه کدهای برنامه شما زیاد شوند و چندین برنامه نویس بخواهند با چنین روشی به دادهها دسترسی پیدا کنند، روش دسترسی به اطلاعات با استفاده از اندیس، مناسب نیست، زیرا افراد برنامه نویس باید بهطور مداوم لیست اطلاعات کارمندان را چک کنند و از این مسئله مطمئن شوند که چه اندیسی، در برگیرنده چه اطلاعاتی از کارمندان است.
به علاوه، چنانچه اطلاعات کارمندان کامل نباشد، طول لیستهای تعریف شده برای هر یک از کارمندان یکسان نخواهد بود و شماره اندیسهای مشابه تمامی لیستها، به اطلاعات یکسانی اشاره نخواهند داشت. در مثالی که ارائه کردیم، اندیس ۱ در لیستهای kirk
و spock
به سن ۲ کارمند اشاره دارد، اما در لیست mccoy
، آیتمی برای سن کارمند لحاظ نشده است و اندیس ۱ از این لیست، عنوان شغلی کارمند را نشان میدهد.
برای رفع چنین مشکلات مهمی، میتوان از شی گرایی در پایتون استفاده کرد و اطلاعات کلیه کارمندان را با تعریف یک کلاس و ساخت اشیای مختلف برای هر یک از کارمندان در برنامه ذخیره کرد.
به عبارتی میتوان گفت شی گرایی در پایتون این امکان را فراهم میکند تا با استفاده از کلاس، بتوان ساختار داده جدیدی را تعریف کرد و برای آن ویژگیها و متدهای مختلفی در نظر گرفت. کلاس، طرح اولیهای از هر ماهیت است و دادهای را در خود ذخیره نمیکند. به منظور ذخیره کردن دادهها با استفاده از کلاس، باید «نمونهای» (وحله | Instance) از کلاس ساخته شود تا بتوان دادههای خود را در آن ذخیره کرد. به هر نمونه ایجاد شده از کلاس، شی گفته میشود. در واقع کلاس «نقشه ساخت» شی به حساب میآید.
در مثالی که برای ذخیره اطلاعات کارمندان ارائه کردیم، میتوان کلاسی را با نام Person ایجاد کرد که درون این کلاس میتوان ویژگیهای مربوط به کارمندان مانند اسم، سن، آدرس، سمت شغلی و تاریخ شروع به کار را تعریف کرد. همچنین عملیات و توابعی که اشیای کلاس کارمند میتوانند پیادهسازی کنند را نیز مِتُدهای کلاس مینامند و این متدها در واقع رفتار اشیای مشتق شده از کلاس را مشخص میکنند. سپس، به منظور ذخیره دادههای هر یک از کارمندان، باید از شی استفاده کرد. در ادامه، به نحوه ساخت کلاس و شی در زبان برنامه نویسی پایتون پرداخته میشود.
نحوه تعریف کلاس و شی در پایتون
همانطور که پیش از این اشاره کردیم، برای استفاده از شی گرایی در پایتون باید در وهله اول، کلاسی برای ماهیت تعیین شده ایجاد کرد.
به منظور تعریف کلاس در پایتون، از کلمه کلیدی class
استفاده میشود. پس از نوشتن این کلمه کلیدی، باید نام کلاس درج شود. برای نوشتن حرف اول نام کلاس باید از حروف بزرگ انگلیسی استفاده کنیم. در نهایت، علامت دو نقطه ( :
) پس از نام کلاس قرار میگیرد. در ادامه، مثالی از نحوه ساخت کلاس برای کلاس Person
ملاحظه میشود.
class Person:
pass
چنانچه نام کلاس از چندین کلمه تشکیل شده باشد، باید کلمات بدون درج فاصله به گونهای نوشته شوند که حروف نخست کلمات، حروف بزرگ انگلیسی باشند. به عنوان مثال، اگر قصد دارید کلاسی برای کارمندان بخش فروش سازمان بسازید، میتوانید از نام SalesEmployee
استفاده کنید.
از کلمه کلیدی pass
در توابع و کلاسهایی استفاده میشود که دستورات در بدنه آنها نوشته نشده باشند. نوشتن این کلمه کلیدی باعث میشود در زمان اجرای برنامه، خطای کامپایلر رخ ندهد. پس از ساخت کلاس، میتوان شیئی را به عنوان وحلهای از کلاس ساخت. در بخش پیشین، از متغیری با عنوان kirk
برای ذخیره اطلاعات یکی از کارمندان استفاده کردیم. از همین نام برای ساخت یک شی جدید از کلاس Person
به روش زیر استفاده میکنیم:
class Person:
pass
kirk = Person()
چنانچه کلاس Person
دارای ویژگیها و متدهای مختلف باشد، با استفاده از شی kirk
میتوان به هر یک از آنها دسترسی داشت و اطلاعات کارمند kirk
را با استفاده از ویژگیها و متد کلاس Person
ذخیره کرد. با استفاده از دستور type()
نیز میتوان کلاس شی تعریف شده را مشخص کرد. در مثال زیر، نحوه کاربرد این تابع ارائه شده است:
print(type(kirk))
خروجی قطعه کد بالا به صورت
است که این خروجی نشان میدهد شی kirk
به عنوان نمونهای از کلاس Person
محسوب میشود. پس از ساخت کلاس Person
و تعریف شی از این کلاس، میتوان با استفاده از تابع isinstance()
مشخص کرد که آیا شی، نمونهای از کلاس Person
است؟ قطعه کد زیر، نحوه استفاده از این تابع را نشان میدهد.
kirk = Person()
print(isinstance(kirk, Person)) # True
خروجی قطعه کد بالا برابر با True است که این مقدار نشان میدهد شی kirk
، نمونهای از کلاس Person
محسوب میشود. در ادامه مطلب، به نحوه تعریف ویژگیها و متدهای کلاس در زبان پایتون پرداخته میشود.
کلاس در پایتون چیست ؟ — آموزش کامل ساخت و استفاده + کد و مثال
تعریف ویژگی های کلاس در پایتون
شی گرایی در پایتون این امکان را برای برنامهنویسان فراهم میکند تا ویژگیهای مختلفی را درون کلاس ایجاد کنند. برای ساخت ویژگی میتوان از تعریف متغیر استفاده کرد.
دو نوع ویژگی میتوانیم در کلاس پایتون بسازیم که در ادامه به آنها اشاره شده است:
- «متغیرهای کلاس» (Class Variables)
- «متغیرهای وحلهای» (Instance Variables)
در ادامه مطلب، به توضیح هر یک از این دو نوع متغیر و نحوه ساخت آنها در پایتون پرداخته میشود.
متغیر کلاس در پایتون چیست ؟
متغیرهای کلاس، نوعی از ویژگیهای درون کلاس هستند که پس از اعلان کلاس تعریف میشوند. این متغیرها خارج از توابع (متدهای) داخل کلاس قرار میگیرند. مقادیر این نوع متغیرها برای تمامی اشیای ساخته شده از کلاس، به اشتراک گذاشته میشوند.
در قطعه کد زیر، متغیرهای extension
و version
مثالهایی از متغیرهای کلاس HtmlDocument
هستند.
class HtmlDocument:
extension = 'html'
version = '5'
به منظور دسترسی به مقادیر متغیرهای کلاس، میتوان از نام کلاس HtmlDocument
به همراه علامت نقطه ( .
) و سپس نام متغیر کلاس استفاده کرد.
class HtmlDocument:
extension = 'html'
version = '5'
print(HtmlDocument.extension) # html
print(HtmlDocument.version) # 5
همچنین، میتوان شیئی از کلاس HtmlDocument
ساخت و با استفاده از نام شی به متغیرهای کلاس دسترسی داشت.
class HtmlDocument:
extension = 'html'
version = '5'
object = HtmlDocument()
print(object.extension) # html
print(object.version) # 5
چنانچه، نام متغیر کلاسی را به اشتباه فراخوانی کنیم و آن متغیر در کلاس تعریف نشده باشد، خطای کامپایلر رخ میدهد.
class HtmlDocument:
extension = 'html'
version = '5'
print(HtmlDocument.media_type)
در قطعه کد بالا، متغیر medi_TYPE
در کلاس HtmlDocument
تعریف نشده است. به همین خاطر، در زمان اجرای قطعه کد بالا، خطای زیر رخ میدهد:
AttributeError: type object 'HtmlDocument' has no attribute 'media_type'
روش دیگری که میتوان از طریق آن به متغیرهای کلاس دسترسی داشت، استفاده از تابع getattr()
است. این تابع، نام شی و نام متغیر کلاس را به عنوان ورودی دریافت میکند و مقدار متغیر کلاس را به عنوان خروجی بازمیگرداند. در قطعه کد زیر، نحوه استفاده از این تابع نشان داده شده است.
class HtmlDocument:
extension = 'html'
version = '5'
extension = getattr(HtmlDocument, 'extension')
version = getattr(HtmlDocument, 'version')
print(extension) # html
print(version) # 5
به منظور تغییر مقادیر متغیرهای کلاس میتوان از نام کلاس و نام شی به روش زیر استفاده کرد:
HtmlDocument.version = 10
object.version = 10
به علاوه، تابع setattr()
را نیز میتوان برای تغییر مقادیر متغیرهای کلاس به کار برد. در قطعه کد زیر، نحوه استفاده از این تابع نشان داده شده است.
setattr(HtmlDocument, 'version', 10)
به منظور اضافه کردن متغیرهای کلاس جدید میتوان از سه روش استفاده کرد. روش اول، اضافه کردن نام متغیر کلاس به همراه مقدار آن درون کلاس تعریف شده است. در روش دوم، میتوان از بیرون کلاس، متغیر کلاس جدیدی را به کلاس تعریف شده از قبل، به روش زیر اضافه کرد:
HtmlDocument.media_type = 'text/html'
print(HtmlDocument.media_type) # text/html
روش سوم برای اضافه کردن متغیر کلاس جدید به کلاس از پیش تعریف شده، استفاده از تابع setattr()
است. در قطعه کد زیر، نحوه استفاده از این تابع نشان داده شده است:
setattr(HtmlDocument, media_type, 'text/html')
print(HtmlDocument.media_type) # text/html
شی گرایی در پایتون این امکان را به برنامهنویسان میدهد تا وقتی به متغیر کلاسی احتیاج نداشتند، آن متغیر را با استفاده از تابع delattr()
و کلمه کلیدی del
از برنامه حذف کنند. در قطعه کد زیر، نحوه استفاده از این دو روش برای حذف متغیرهای کلاس HtmlDocument
ملاحظه میشود.
delattr(HtmlDocument, 'version')
del HtmlDocument.extension
متغیرهای وحله ای در کلاس های پایتون
متغیرهای نمونه، متغیرهایی هستند که درون توابع (متدها) و «سازندهها» (Constructors) تعریف میشوند. مقادیر این متغیرها برای هر یک از اشیای ساخته شده از یک کلاس مشابه، متفاوت هستند.
به عبارتی، این نوع متغیرها مختص اشیاء هستند و مقادیرشان بین اشیاء مختلف کلاس به اشتراک گذاشته نمیشوند. به منظور مقداردهی اولیه متغیرهای نمونه، میتوان از متد __init__()
درون کلاس استفاده کرد. زمانی که شی جدیدی را از یک کلاس ایجاد میکنید، بهطور خودکار، متد __init__()
فراخوانی میشود. بدین ترتیب، میتوان از این متد برای مقداردهی اولیه مشخصههای اشیاء استفاده کرد. در قطعه کد زیر، مثالی از نحوه مقداردهی اولیه متغیرهای نمونه در کلاس Person
ملاحظه میشود.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
object_person = Person('John', 25)
print(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
است که به شی اشاره دارد. در ادامه، قطعه کدی ملاحظه میشود که نحوه تعریف متد نمونه کلاس را نشان میدهد.
class Request:
def send(self):
print('Sent')
http_request = Request()
print(http_request.send()) # Sent
متد کلاس در پایتون
با استفاده از شی گرایی در پایتون میتوان متدهایی از نوع متد کلاس تعریف کرد که از طریق آنها میتوان مقادیر متغیرهای کلاس را تغییر داد. همانطور که در بخش مربوط به متغیر کلاس توضیح داده شد، مقادیر این نوع متغیرها برای تمامی اشیاء ساخته شده از یک کلاس مشابه، به اشتراک گذاشته میشوند.
متدهای کلاس را میتوان به دو روش در پایتون ایجاد کرد. در اولین روش، از «دکوراتوری» (Decorator) با نام @classmethod
استفاده میشود که در ادامه قطعه کدی از کاربرد این دکوراتور در ساخت متد کلاس ارائه شده است.
from datetime import date
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def calculate_age(cls, name, birth_year):
# calculate age an set it as a age
# return new object
return cls(name, date.today().year - birth_year)
def show(self):
print(self.name + "'s age is: " + str(self.age))
# create new object using the factory method
joy = Student.calculate_age("Joy", 1995)
joy.show()
در مثال بالا، متد calculate_age
از نوع متد کلاس است. خاطر نشان میشود نخستین پارامتر متد کلاس باید مقدار cls
باشد که به نام کلاس جاری اشاره میکند.
روش دیگری که با کمک آن میتوان متد کلاس تعریف کرد، استفاده از تابع classmethod
است. به هنگام استفاده از این تابع، باید متدی را درون کلاس تعریف کرد و نام متد را به عنوان آرگومان تابع classmethod
در نظر گرفت تا این تابع، متد مشخص شده را به متد کلاس تبدیل کند. در قطعه کد زیر، مثالی از کاربرد تابع classmethod
برای ساخت متد کلاس school_name
ملاحظه میشود.
class School:
# class variable
name = 'ABC School'
def school_name(cls):
print('School Name is :', cls.name)
# create class method
School.school_name = classmethod(School.school_name)
# call class method
School.school_name()
اصول شی گرایی در پایتون
برنامه نویسی شی گرا علاوه بر مفاهیم شی و کلاس، شامل چهار اصل مهم هم هست که با لحاظ کردن این اصول در توسعه پروژههای نرمافزاری، میزان بهرهوری برنامهها بیشتر میشود و برنامهنویسان میتوانند به راحتی، قطعه کدهای نوشته شده را بهروزرسانی و آنها را گستردهتر کنند.
همچنین، با رعایت اصول شی گرایی میتوان سطح امنیت برنامه نویسی را بالا برد و کدها را به صورت ماژولار نوشت که همین امر باعث میشود میزان خوانایی برنامهها بیشتر شود و بتوان به آسانی، از قطعه کدهای نوشته شده در سایر پروژههای نرمافزاری به دفعات استفاده کرد. چهار اصل مهم شی گرایی در پایتون و در سایر زبانهای برنامه نویسی شی گرا در ادامه فهرست شدهاند:
- اصل «کپسولهسازی» (Encapsulation)
- اصل «انتزاع | تجرید» (Abstraction)
- «وراثت | ارثبری» (Inheritance)
- «پلی مورفیسم | چندریختی» (Polymorphism)
در ادامه مطلب، به توضیح مفاهیم هر یک از اصول شی گرایی در پایتون پرداخته و مثالهای کاربردی برای آنها ارائه میشود تا خوانندگان مطلب حاضر با نحوه پیادهسازی قطعه کدهای برنامه بر اساس این چهار اصل آشنا شوند.
اصول برنامه نویسی شی گرا — به زبان ساده
اصل وراثت شی گرایی در پایتون چیست ؟
یکی از اصول شی گرایی در پایتون، اصل وراثت یا ارثبری است که در طی این فرآیند، میتوان کلاسی را ایجاد کرد که ویژگیها و متدهای خود را از کلاس دیگری به ارث ببرد که از قبل تعریف شده است. در این حال، کلاس جدید، کلاس فرزند (Child Class) نام دارد و به کلاسی که مشخصههای خود را به کلاس فرزند میدهد، کلاس والد (Parent Class) گفته میشود.
کلاس فرزند میتواند ویژگیها و متدهایی را که از کلاس والد به ارث برده است، بنا به نیاز خود تغییر دهد. چنانچه بخواهیم مثال قابل درکی از دنیای واقعی برای اصل وراثت ارائه دهیم، میتوان به ژنهای پدر و مادر و انتقال آنها به فرزندانشان اشاره کرد.
ممکن است فرزند رنگ موی خود را از مادرش به ارث ببرد. با این حال، فرزند تصمیم میگیرد رنگ موی خود را تغییر دهد و موی خود را به رنگ صورتی تغییر دهد. با اینکه فرزند، داشتن ویژگی رنگ مو را از پدر و مادر خود به ارث برده است، اما میتواند به تصمیم خود، رنگ آن را تغییر دهد و موی خود را به رنگی درآورد که مشابه رنگ موی پدر و مادر خود نیست.
شی گرایی در پایتون نیز بر اساس تعاریفی که از وراثت و نحوه ارثبری در دنیای حقیقی وجود دارد، این امکان را به برنامه نویس میدهد تا از کلاسی که ساخته شده است، بتوان به دفعات مختلف به شیوهای استفاده کرد که مشخصههای کلاس، مطابق نیاز کاربر تغییر کنند. به منظور درک بهتر این اصل، مثالی از پایتون ارائه میکنیم.
فرض کنید کلاسی با نام Person
ساخته شده است که مشخصههای __init__
و greet
را دارد. در قطعه کد زیر، مثالی از این کلاس ملاحظه میشود.
class Person:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hi, it's {self.name}"
حال میخواهیم کلاسی با نام Employee
ایجاد کنیم که دقیقاً مشخصههای کلاس Person
را داشته باشد. در قطعه کد زیر، نحوه ساخت کلاس Person
ملاحظه میشود.
class Employee:
def __init__(self, name, job_title):
self.name = name
self.job_title = job_title
def greet(self):
return f"Hi, it's {self.name}"
همانطور که در قطعه آمده است، کلاس Employee
دارای متد greet
است که همین متد در کلاس Person
نیز وجود دارد. با استفاده از اصل وراثت در شی گرایی پایتون، میتوان متد greet
را از کلاس Employee
حذف کرد و با ایجاد ارتباط بین دو کلاس Employee
و Person
، متد greet
را از کلاس Person
به ارث برد. در این حالت، کلاس Employee
به عنوان کلاس فرزند و کلاس Person
به عنوان کلاس والد مشخص میشوند. در ادامه، نحوه بهکارگیری اصل وراثت در پایتون ملاحظه میشود.
class Employee(Person):
def __init__(self, name, job_title):
self.name = name
self.job_title = job_title
همانطور که در قطعه کد بالا دیده میشود، میتوان در خط اعلان کلاس فرزند، نام کلاس والد را در داخل پرانتز قرار داد. بدین ترتیب، کلاس Employee
علاوه بر ویژگیهای name
و job_title
، دارای متد greet
نیز هست که آن را از کلاس والد خود، یعنی کلاس Person
، به ارث میبرد. در ادامه، مثالی از نحوه دسترسی به متد greet
از طریق شی ساخته شده از کلاس Employee
ملاحظه میشود.
employee = Employee('John', 'Python Developer')
print(employee.greet())
خروجی قطعه کد بالا در ادامه نشان داده شده است:
Hi, it's John
با استفاده از تابع issubclass()
میتوان مشخص کرد که آیا دو کلاس رابطه والد – فرزندی دارند؟ در ادامه، نحوه استفاده از این تابع در زبان پایتون در قالب مثال، نشان داده شده است:
print(issubclass(Employee, Person)) # True
همچنین، با استفاده از super()
میتوان از داخل کلاس فرزند، به متدهای کلاس والد دسترسی داست. در ادامه، قطعه کدی از زبان پایتون ارائه شده است که نحوه استفاده از super()
را نشان میدهد.
class Employee:
def __init__(self, name, base_pay, bonus):
self.name = name
self.base_pay = base_pay
self.bonus = bonus
def get_pay(self):
return self.base_pay + self.bonus
class SalesEmployee(Employee):
def __init__(self, name, base_pay, bonus, sales_incentive):
super().__init__(name, base_pay, bonus)
self.sales_incentive = sales_incentive
def get_pay(self):
return super().get_pay() + self.sales_incentive
if __name__ == '__main__':
sales_employee = SalesEmployee('John', 5000, 1000, 2000)
print(sales_employee.get_pay()) # 8000
اصل وراثت میتواند از راههای مختلف در برنامه نویسی استفاده شود. به عبارتی، انواع مختلفی از ارثبری در شی گرایی وجود دارد که در ادامه به آنها اشاره شده است.
- «وراثت منفرد» (Single Inheritance)
- «وراثت چندگانه» (Multiple Inheritance)
- «وراثت چند سطحی» (Multi-Level Inheritance)
- «وراثت سلسلهمراتبی» (Hierarchical Inheritance)
- «وراثت ترکیبی» (Hybrid Inheritance)
در ادامه مطلب حاضر، به توضیح هر یک از انواع وراثت پرداخته میشود و مثالی کاربردی از زبان پایتون برای هر یک از آنها ارائه خواهد شد.
وراثت منفرد در پایتون
یکی از انواع نحوه ارثبری در شی گرایی، نوع ارثبری منفرد است. در این نوع وراثت، هر کلاس فرزند تنها دارای یک کلاس والد است و تمامی ویژگیها و متدهای کلاس والد را به ارث میبرد. در مثال زیر، نحوه ارثبری کلاس فرزند از یک کلاس والد در پایتون ملاحظه میشود.
و Person
ارائه شد، از نوع وراثت منفرد است.
وراثت چندگانه شی گرایی در پایتون چیست ؟
زمانی که چندین کلاس وجود داشته باشند و بخواهیم کلاس جدیدی را به عنوان کلاس فرزند ایجاد کنیم که تمامی مشخصههای کلاسهای موجود را به ارث ببرد، از وراثت چندگانه استفاده میکنیم.
به منظور ایجاد وراثت چندگانه در پایتون، کافی است در زمان اعلان کلاس فرزند، نام تمامی کلاسهای والد در داخل پرانتز نوشته شوند. در ادامه، ساختار نحوی وراثت چندگانه در پایتون ملاحظه میشود.
#syntax_of_multiple_inheritance
class parent_1:
pass
class parent_2:
pass
class child(parent_1,parent_2):
pass
obj = child()
مثال زیر نیز، قطعه کدی از زبان پایتون را نشان میدهد که در آن دو کلاس والد با نامهای Brands
و Products
ساخته شدهاند و کلاس فرزندی نیز با نام Popularity
تعریف شده است که از دو کلاس والد ارثبری میکند.
#example_of_multiple_inheritance
class Brands: #parent_class
brand_name_1 = "Amazon"
brand_name_2 = "Ebay"
brand_name_3 = "OLX"
class Products: #child_class
prod_1 = "Online Ecommerce Store"
prod_2 = "Online Store"
prod_3 = "Online Buy Sell Store"
class Popularity(Brands,Products):
prod_1_popularity = 100
prod_2_popularity = 70
prod_3_popularity = 60
obj_1 = Popularity() #Object_creation
print(obj_1.brand_name_1+" is an "+obj_1.prod_1))
print(obj_1.brand_name_2+" is an "+obj_1.prod_2))
print(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
وراثت چندسطحی در شی گرایی در پایتون چیست ؟
وراثت چندسطحی شی گرایی در پایتون این امکان را فراهم میآورد تا کلاس فرزند، از کلاسی ارثبری کند که آن کلاس، خودش به عنوان کلاس فرزند محسوب میشود. به عبارتی، کلاس فرزند، علاوه بر کلاس والد خود، از کلاس والد والد خود نیز ارثبری میکند. در ادامه، ساختار نحوی پایتون برای تعریف وراثت چندسطحی ملاحظه میشود.
#Syntax_of_multilevel_inheritance
class A:
pass
class B(A):
pass
class C(B):
pass
obj = C()
مثال زیر، نمونهای از نحوه پیادهسازی اصل وراثت از نوع چندسطحی را در پایتون نشان میدهد. در این مثال، کلاس Produsts
به عنوان کلاس والد برای کلاس Popularity
تعریف شده است که خودش به عنوان کلاس فرزند برای کلاس Brands
محسوب میشود. بدین ترتیب، کلاس Popularity
از مشخصههای کلاسهای Products
و Brands
ارثبری میکند.
class Brands: #parent_class
brand_name_1 = "Amazon"
brand_name_2 = "Ebay"
brand_name_3 = "OLX"
class Products(Brands): #child_class
prod_1 = "Online Ecommerce Store"
prod_2 = "Online Store"
prod_3 = "Online Buy Sell Store"
class Popularity(Products): #grand_child_class
prod_1_popularity = 100
prod_2_popularity = 70
prod_3_popularity = 60
obj_1 = Popularity() #Object_creation
print(obj_1.brand_name_1+" is an "+obj_1.prod_1+" popularity of "+str(obj_1.prod_1_popularity))
print(obj_1.brand_name_2+" is an "+obj_1.prod_2+" popularity of "+str(obj_1.prod_2_popularity))
print(obj_1.brand_name_3+" is an "+obj_1.prod_3+" popularity of "+str(obj_1.prod_3_popularity))
#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
وراثت سلسله مراتبی شی گرایی در پایتون چیست ؟
وراثت سلسله مراتبی این امکان را فراهم میکند تا یک کلاس والد تعریف کنیم و کلاسهای فرزند مختلفی بسازیم که از آن کلاس والد ارثبری میکنند. ساختار نحوی این نوع وراثت در زبان پایتون به شکل زیر است:
#syntax_of_hierarchical_inheritance
class A: #parent_class
pass
class B(A): #child_class
pass
class C(A): #child_class
pass
class D(A): #child_class
pass
obj_1 = B() #Object_creation
obj_2 = C()
obj_3 = D()
در مثال زیر، نمونهای از وراثت سلسله مراتبی در پایتون ملاحظه میشود. در این مثال، کلاسهای فرزند Popularity
، Value
و Products
از تنها کلاس والد Brands
ارثبری میکنند.
#example
class Brands: #parent_class
brand_name_1 = "Amazon"
brand_name_2 = "Ebay"
brand_name_3 = "OLX"
class Products(Brands): #child_class
prod_1 = "Online Ecommerce Store"
prod_2 = "Online Store"
prod_3 = "Online Buy Sell Store"
class Popularity(Brands): #grand_child_class
prod_1_popularity = 100
prod_2_popularity = 70
prod_3_popularity = 60
class Value(Brands):
prod_1_value = "Excellent Value"
prod_2_value = "Better Value"
prod_3_value = "Good Value"
obj_1 = Products() #Object_creation
obj_2 = Popularity()
obj_3 = Value()
print(obj_1.brand_name_1+" is an "+obj_1.prod_1)
print(obj_1.brand_name_1+" is an "+obj_1.prod_1)
print(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
وراثت ترکیبی در پایتون
آخرین نوع وراثت در شی گرایی پایتون، وراثت ترکیبی است. این نوع وراثت، ترکیبی از انواع روشهای قبلی ارثبری است که تا به الان توضیح داده شدند. به عبارتی، میتوان گفت در وراثت ترکیبی میتوان از ترکیب وراثت ساده، وراثت چندسطحی، وراثت چندگانه و وراثت سلسله مراتبی استفاده کرد.
نمونهای از ساختار نحوی پایتون را برای تعریف وراثت ترکیبی در ادامه ملاحظه میکنید.
#Syntax_Hybrid_inheritance
class PC:
pass
class Laptop(PC):
pass
class Mouse(Laptop):
pass
class Student3(Mouse, Laptop):
pass
# Driver's code
obj = Student3()
در ادامه نیز، قطعه کدی از زبان پایتون ارائه شده است که مثالی از وراثت ترکیبی را نشان میدهد.
#Example_Hybrid_inheritance
class PC:
def fun1(self):
print(“This is PC class”)
class Laptop(PC):
def fun2(self):
print(“This is Laptop class inheriting PC class”)
class Mouse(Laptop):
def fun3(self):
print(“This is Mouse class inheriting Laptop class”)
class Student(Mouse, Laptop):
def fun4(self):
print(“This is Student class inheriting PC and Laptop”)
# Driver’s code
obj = Student()
obj1 = Mouse()
obj.fun4()
obj.fun3()
اصل کپسوله سازی شی گرایی در پایتون چیست ؟
یکی دیگر از اصول شی گرایی، اصل کپسولهسازی است که با کمک آن میتوان تمام مشخصههای مربوط به دادهها را در یک بخش مجزا در برنامه نویسی قرار داد و دسترسی به آنها را مدیریت کرد. ساخت کلاس و تعریف مشخصهها درون آن، میتواند بستری را برای پیادهسازی اصل کپسولهسازی فراهم کند.
به عبارتی، تمامی ویژگیها و متدهای یک ماهیت، در یک کلاس تعریف میشوند و میتوان مشخص کرد که با تعریف شی به کدام یک از این مشخصهها میتوان دسترسی داشت. بر اساس اصل کپسولهسازی شی گرایی، میتوان سه نوع سطح دسترسی به مشخصههای درون کلاس اختصاص داد که در ادامه به آنها اشاره شده است:
- مشخصههایی از نوع «عمومی» (Public)
- مشخصههایی از نوع «خصوصی» (Private)
- مشخصههایی از نوع «محافظت شده» (Protected)
در ادامه، به توضیح هر یک از انواع سطوح دسترسی به مشخصههای کلاس پرداخته میشود.
مشخصه های عمومی کلاس در پایتون
مشخصههای عمومی کلاس در شی گرایی به مشخصههایی گفته میشود که بدون هیچ محدودیتی بتوان به آنها دسترسی داشت. به عبارتی، ویژگیها و متدهای عمومی کلاس را میتوان از خارج کلاس (با استفاده از اشیای تعریف شده) یا از طریق کلاسهای فرزند مدیریت کرد و به مقادیر آنها دسترسی داشت.
در قطعه کد زیر، مثالی از مشخصههای عمومی کلاس در زبان پایتون ارائه شده است. در این مثال، ویژگیهای name
و age
و متد print_name
به عنوان مشخصههای عمومی کلاس Person
محسوب میشوند که با استفاده از شی object_person
میتوان از خارج کلاس، به آنها دسترسی داشت.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print('The name is :' , self.name)
object_person = Person('John', 25)
print(object_person.name)
object_person.print_name()
مشخصه های محافظت شده کلاس در پایتون
اصل کپسولهسازی شی گرایی این امکان را فراهم میکند تا بتوان مشخصههایی در کلاس ایجاد کرد که از خارج کلاس، امکان دسترسی به آنها وجود ندارد. تنها راه دسترسی به مشخصههای محافظت شده، از درون کلاس یا از داخل کلاسهای فرزند است. این اصل باعث بالا بردن سطح امنیت در توسعه برنامه میشود.
در زبان برنامه نویسی پایتون، بر خلاف سایر زبانهای برنامه نویسی، منع دسترسی به مشخصههای حفاظت شده از خارج کلاس وجود ندارد. به عبارتی، تعریف مشخصههای حفاظت شده به عنوان قراردادی بین برنامهنویسان این زبان است که صرفاً از نوع مشخصه آگاه باشند. بدین ترتیب، چنانچه از این مشخصهها در خارج از کلاس استفاده شود، خطای کامپایلر رخ نمیدهد. به منظور تعریف مشخصههای حفاظت شده در پایتون از علامت ( _
) استفاده میشود.
در قطعه کد زیر، مثالی از نحوه کاربرد ویژگیهای محافظت شده در پایتون ارائه شده است. در این مثال، متغیر _q
از نوع متغیر محافظت شده است که نام آن با علامت ( _
) آغاز میشود.
class Base1:
def __init__(self):
self._q = "Javatpoint"
obj_1 = Base1()
print(obj_1._q)
خروجی قطعه کد بالا، در ادامه آمده است.
Javatpoint
به منظور تعریف متدهای محافظت شده درون کلاس نیز میتوان قبل از نام متد، از علامت _
در پایتون استفاده کرد. در قطعه کد زیر، مثالی از نحوه تعریف متد محافظت شده در زبان پایتون ارائه شده است. همانطور که در این مثال ملاحظه میشود، متد _warmup
از نوع متد محافظت شده به حساب میآید.
class Person:
def __init__(self, name):
self.name = name
def _warmup(self):
print("{} is warming up".format(self.name))
jack = Person ('Jack')
jack._warmup()
خروجی قطعه کد بالا در ادامه ملاحظه میشود.
Jack is warming up
مشخصه های خصوصی کلاس در پایتون
مشخصههای خصوصی در شی گرایی نیز دارای محدودیتهای دسترسی هستند. به عبارتی، به این نوع مشخصهها نمیتوان از خارج کلاس دسترسی داشت. علاوه بر این، کلاسهای فرزند نیز محدودیت دسترسی به مشخصههای خصوصی کلاس والد خود را دارند. بدین ترتیب، مشخصههای خصوصی تنها از درون کلاس قابل دسترس هستند.
بر خلاف سایر انواع زبانهای برنامه نویسی، پایتون، مانع دسترسی به مشخصههای حفاظت شده از خارج کلاس نمیشود. به عبارتی، تعریف مشخصههای خصوصی درون کلاس، به عنوان قراردادی بین برنامهنویسان این زبان محسوب میشود که صرفاً از نوع مشخصه آگاه باشند.
بدین ترتیب، چنانچه با کلاسهای فرزند یا از طریق شی ساخته شده از بیرون کلاس بخواهیم به مشخصههای خصوصی در پایتون دسترسی داشته باشیم، خطای کامپایلر رخ نخواهد داد. به منظور تعریف ویژگیها و متدهای خصوصی در پایتون از علامت ( __
) در ابتدای نام مشخصهها استفاده میشود. در ادامه، مثالی از نحوه کاربرد ویژگی خصوصی در زبان پایتون ارائه شده است:
class Base1:
def __init__(self):
self.__q = "Javatpoint"
obj_1 = Base1()
print(obj_1.__q)
خروجی قطعه کد بالا، در ادامه ملاحظه میشود.
Javatpoint
برای تعریف متدهای خصوصی درون کلاس در زبان پایتون نیز میتوان قبل از نام متد، از علامت ( __
) استفاده کرد. در قطعه کد زیر، مثالی از نحوه تعریف متد خصوصی در این زبان برنامه نویسی ارائه شده است.
class Person:
def __init__(self, name):
self.name = name
def __warmup(self):
print("{} is warming up".format(self.name))
jack = Person ('Jack')
jack.__warmup()
خروجی قطعه کد بالا در ادامه ملاحظه میشود.
Jack is warming up
اصل انتزاع شی گرایی در پایتون
اصل انتزاع در شی گرایی این امکان را فراهم میآورد تا بتوانیم کلاس انتزاعی بسازیم. کلاس Abstract یا همان انتزاعی نمونه اولیهای از یک کلاس است که با تعریف کلاسهای فرزند میتوان از متدهای آن کلاس ارثبری کرد. به منظور استفاده از کلاسهای انتزاعی، نمیتوان بهطور مستقیم از آنها شی ساخت.
به عبارتی، باید کلاسهای فرزندی را ایجاد کرد که از کلاسهای انتزاعی ارثبری میکنند و سپس با تعریف اشیای جدید از کلاسهای فرزند، بتوان به متدهای کلاسهای انتزاعی دسترسی داشت. کلاس انتزاعی شامل «متدهای انتزاعی» (Abstract Method) میشود.
متدهای انتزاعی، متدهایی هستند که صرفاً اعلان شدهاند اما بدنه آنها تعریف نشده است. کلاسهای انتزاعی زمانی کاربرد دارند که بخواهیم کلاسهای مختلفی ایجاد کنیم که دارای متدهایی با نامهای یکسان باشند، اما با استفاده از روش «بازنویسی متد» (Method Overriding)، دستورات متفاوتی را برای این متدها در کلاسهای فرزند تعریف کنیم.
بر خلاف کلاسهای عادی در پایتون، برای تعریف کلاس انتزاعی باید از کتابخانه استفاده کرد. به عبارتی، بهطور مستقیم نمیتوان کلاس انتزاعی را در زبان پایتون تعریف کرد و باید از کتابخانهای با نام abc
استفاده شود. در این کتابخانه، ماژولی با نام ABC
وجود دارد که باید برای تعریف کلاس انتزاعی در پایتون فراخوانی شود. برای ساخت متد انتزاعی در پایتون نیز پیش از خط اعلان متد، از دستور abc.abstractmethod
استفاده میشود.
در قطعه کد زیر، مثالی از نحوه تعریف کلاس انتزاعی در زبان پایتون ارائه شده است. در این مثال، کلاس AbstractClassName
از نوع کلاس انتزاعی است که ماژول ABC
در خط اعلان این کلاس صدا زده میشود. متد abstract_method_name
نیز متد انتزاعی کلاس است که با استفاده از دکوراتور @abstractmethod
به عنوان متد انتزاعی در نظر گرفته میشود.
from abc import ABC, abstractmethod
class AbstractClassName(ABC):
@abstractmethod
def abstract_method_name(self):
pass
خاطر نشان میشود از آنجایی که متدهای انتزاعی دارای بدنه نیستند و بدنه آنها درون کلاس فرزند باید بازنویسی شوند، باید در قسمت بدنه متدهای انتزاعی در پایتون از دستور pass
استفاده شود تا در زمان اجرای برنامه، خطای کامپایلر رخ ندهد.
کلاس Abstract در پایتون — به زبان ساده
در قطعه کد زیر، مثالی کاربردی از کلاس انتزاعی و نحوه ارثبری از آن ارائه شده است. در این مثال، کلاس Employee
، کلاس انتزاعی است که یک متد انتزاعی با نام get_salary
دارد. کلاسهای FulltimeEmployee
و HuprlyEmployee
کلاسهای فرزند هستند که با روش بازنویسی متد، بدنه متد get_salary
در این کلاسها با دستورات متفاوت تکمیل شده است.
from abc import ABC, abstractmethod
class Employee(ABC):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@abstractmethod
def get_salary(self):
pass
class FulltimeEmployee(Employee):
def __init__(self, first_name, last_name, salary):
super().__init__(first_name, last_name)
self.salary = salary
def get_salary(self):
return self.salary
class HourlyEmployee(Employee):
def __init__(self, first_name, last_name, worked_hours, rate):
super().__init__(first_name, last_name)
self.worked_hours = worked_hours
self.rate = rate
def get_salary(self):
return self.worked_hours * self.rate
اصل چندریختی در پایتون
اصل «چندریختی | پلی مورفیسم» (Polymorphism) یکی دیگر از اصول مهم شیگرایی است و به وضعیتی اطلاق میشود که ماهیتی نظیر متد، «عملگر» (Operator) یا شی در شرایط مختلف، رفتار متفاوتی داشته باشند.
اصل چندریختی در شی گرایی با دو مفهوم «بازنویسی متد» (Method Overriding) و «سربارگذاری متد» (Method Overloading) سر و کار دارد. در بخش مربوط به اصل انتزاع به توضیح مفهوم بازنویسی متد پرداخته شد. از این روش در مواقعی استفاده میشود که در کلاس فرزند، متدی همنام با متد کلاس والد ایجاد شود، به طوری که این متد شامل دستوراتی مغایر با دستورات متد کلاس والد باشد. به عبارتی، میتوان گفت با اصل چندریختی، یک متد در کلاسهای مختلف (در کلاسهای فرزند) عملکرد متفاوتی دارد.
سربارگذاری متد از دیگر مفاهیمی است که با اصل چندریختی پیادهسازی میشود. سربارگذاری متد زمانی رخ میدهد که کلاس دارای متدی است که تعداد پارامترهای متفاوتی را در ورودی میتواند توسط شی دریافت کند. قطعه کد زیر، مثالی از روش سربارگذاری متد با استفاده از اصل چندریختی در زبان پایتون است.
class Example:
def multiply(self,a,b,c=1):
print(a*b*c)
example = Example()
example.multiply(5,10)
example.multiply(2,5,6)
در مثال بالا ملاحظه میشود که کلاس Example
دارای متدی با نام multiply
است که در ورودی سه پارامتر را دریافت میکند. اشیایی که مقداری برای پارامتر سوم نداشته باشند، به صورت پیشفرض، مقدار عددی ۱ برای آنها لحاظ میشود. بدین ترتیب، بر اساس اصل چندریختی میتوان متدی ایجاد کرد که تعداد مقادیر ارسالی به آنها از طریق اشیای کلاس، متفاوت باشد.
پلی مورفیسم در برنامه نویسی چیست ؟ — مفهوم به زبان ساده + مثال
مدیریت ویژگی در کلاس های پایتون
گاهی لازم است برای دسترسی به ویژگیهایی که در کلاس وجود دارند، محدودیتهایی را لحاظ کنیم. به عنوان مثال، چنانچه کلاسی برای ماهیت Person تعریف کرده باشیم که دارای ویژگیهای مختلفی نظیر اسم و سن باشد، میتوان برای ویژگی سن، محدودیتی لحاظ کرد تا کاربر، این ویژگی را با مقادیر منفی مقداردهی نکند.
برای اعمال محدودیت بر روی ویژگیهای کلاس، میتوان از دو متد getter و setter در داخل کلاس استفاده کرد. به منظور درک بهتر مطلب حاضر، بهتر است مثالی در این باره ارائه کنیم. قطعه کد زیر را در نظر بگیرید که کلاسی را با نام Person
با ویژگیهای name
و age
تعریف میکند.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
john = Person('John', 18)
از آنجایی که age
به عنوان ویژگی نمونه تعریف شده است، میتوان در ادامه برنامه، مقادیر آن را تغییر داد:
john.age = 19
...
...
...
john.age = -1
با این حال، تخصیص مقادیر منفی به ویژگی age
به لحاظ معنایی صحیح نیست. راهحل سادهای که برای چنین مشکلی وجود دارد، این است که در قسمتهایی از برنامه که مقدار ویژگی age
تغییر میکند، شرطی را برای بررسی بازه مقدار عددی آن به صورت زیر در نظر بگیریم:
age = -1
if age
با این حال، این روش باعث افزایش تعداد کدهای تکراری برنامه میشود و چنین راهحلی بهینه نیست. به جای استفاده از این روش، میتوان از دو متد getter و setter در داخل کلاس استفاده کرد تا بر روی اعمال تغییرات در مقادیر ویژگیها نظارتی انجام شود. به عبارتی، متدهای getter و setter به عنوان رابطی برای دسترسی به ویژگیهای نمونه کلاس در پایتون محسوب میشوند. وظیفه این دو متد به شرح زیر است:
- متد getter مقدار ویژگی نمونه را در خروجی بازمیگرداند.
- متد setter مقدار جدیدی را برای ویژگی نمونه لحاظ میکند.
در قطعه کد زیر، مثالی از نحوه تعریف متدهای getter و setter برای ویژگی age
ارائه شده است. خاطر نشان میشود به منظور استفاده از متدهای getter و setter بر اساس قرارداد، نوع ویژگی age
را که از نوع عمومی است، به نوع محافظت شده (یعنی _age
) تبدیل میکنیم.
class Person:
def __init__(self, name, age):
self.name = name
self.set_age(age)
def set_age(self, age):
if 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
محسوب میشود.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def set_age(self, age):
if age
چنانچه مقدار ویژگی age
را با استفاده از شی john
از خارج کلاس تغییر دهید، پایتون متد set_age()
را از طریق آرگومان fset
فراخوانی میکند و مقدار ویژگی age
را تغییر میدهد. به منظور نمایش مقدار ویژگی age
در خروجی با استفاده از شیٔ در خارج از کلاس، میتوان از دستور زیر استفاده کرد:
print(john.age)
علاوه بر روش بالا، میتوان مستقیماً متد get_age()
را با استفاده از شی به صورت زیر فراخوانی کرد:
print(john.get_age())
تمرین برنامه نویسی شی گرا با زبان پایتون
در این بخش، چندین سوال و تمرین برنامه نویسی مرتبط با شی گرایی در پایتون ارائه میکنیم تا خوانندگان این مطلب، دانش خود را که از مطالعه محتوای آموزشی بخشهای پیشین مطلب حاضر کسب کردهاند، مورد سنجش قرار دهند.
در ابتدا، سوالات برنامه نویسی مطرح میشوند و سپس خوانندگان مطلب، میتوانند پاسخ خود را با راهحل ارائه شده مقایسه و از پاسخ خود اطمینان حاصل کنند. پیشنهاد میشود حتماً پیش از مشاهده پاسخ صحیح، مخاطبان خودشان نسبت به حل تمرینها حداکثر تلاش خود را به کار گیرند و در نهایت پاسخ هود را با پاسخ صحیح مقایسه کنند. به این طریق یادگیری بسیار بهتر اتفاق خواهد افتاد.
تمرین ۱. تعریف کلاس در پایتون
با استفاده از پایتون، کلاسی با نام Vehicle
ایجاد کنید که هیچ گونه مشخصهای نداشته باشد.
پاسخ تمرین ۱
پاسخ این تمرین به صورت زیر است:
class Vehicle:
pass
تمرین ۲. تعریف مشخصه های کلاس و شی در پایتون
با استفاده از زبان برنامه نویسی پایتون، کلاسی با نام Vehicle
را ایجاد کنید که دارای دو متغیر نمونه با نامهای max_speed
و mileage
باشد. سپس شیئ از این کلاس ایجاد کنید که با استفاده از آن، دو متغیر نمونه، با مقادیر دلخواه مقداردهی شوند. در نهایت، مقادیر متغیرهای نمونه را با استفاده از شی تعریف شده، در خروجی چاپ کنید.
پاسخ تمرین ۲
جواب تمرین ۲ در ادامه آمده است.
class Vehicle:
def __init__(self, max_speed, mileage):
self.max_speed = max_speed
self.mileage = mileage
modelX = Vehicle(240, 18)
print(modelX.max_speed, modelX.mileage)
تمرین ۳. ارث بری در پایتون
با زبان پایتون قطعه کدی بنویسید که کلاس فرزندی را با نام Bus
ایجاد کند که تمامی مشخصههای خود را از کلاس والد Vehicle
به ارث میبرد. مشخصههای کلاس والد میتوانند شامل متغیرهای نمونه name
، max_speed
و mileage
باشند. سپس مشخصههای کلاس فرزند را با مقادیر دلخواه مقداردهی کنید و در نهایت مقادیر آنها را در خروجی نشان دهید.
پاسخ تمرین ۳
پاسخ این تمرین در ادامه مشاهده میشود.
class Vehicle:
def __init__(self, name, max_speed, mileage):
self.name = name
self.max_speed = max_speed
self.mileage = mileage
class Bus(Vehicle):
pass
School_bus = Bus("School Volvo", 180, 12)
print("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
را در کلاس فرزند با استفاده از بازنویسی متد به نحوی تغییر دهید که مقدار پیشفرض ۵۰ برای پارامتر این تابع در نظر گرفته شود.
پاسخ تمرین ۴
پاسخ تمرین ۴ به صورت زیر است.
class Vehicle:
def __init__(self, name, max_speed, mileage):
self.name = name
self.max_speed = max_speed
self.mileage = mileage
def seating_capacity(self, capacity):
return f"The seating capacity of a {self.name} is {capacity} passengers"
class Bus(Vehicle):
# assign default value to capacity
def seating_capacity(self, capacity=50):
return super().seating_capacity(capacity=50)
School_bus = Bus("School Volvo", 180, 12)
print(School_bus.seating_capacity())
تمرین ۵. متغیرهای کلاس در پایتون
با استفاده از زبان برنامه نویسی پایتون قطعه کدی برای ساخت کلاس والد با نام Vehicle
بنویسید که علاوه بر متغیرهای نمونه name
، max_speed
و mileage
، متغیر کلاسی با نام Color
نیز داشته باشد تا مقدار این متغیر برای تمامی اشیای ساخته شده از کلاس والد و تمامی کلاسهای فرزند آن به اشتراک گذاشته شود.
کلاسهای فرزندی با نامهای Bus
و Car
نیز ایجاد کنید که از کلاس Vehicle
ارثبری میکنند. برای هر یک از این کلاسهای فرزند، شیئی بسازید و مقادیری برای متغیرهای نمونه آنها تعریف کنید. در نهایت، مقادیر تمامی مشخصههای اشیاء را در خروجی نشان دهید.
پاسخ تمرین ۵
پاسخ این تمرین در ادامه آمده است.
class Vehicle:
# Class attribute
color = "White"
def __init__(self, name, max_speed, mileage):
self.name = name
self.max_speed = max_speed
self.mileage = mileage
class Bus(Vehicle):
pass
class Car(Vehicle):
pass
School_bus = Bus("School Volvo", 180, 12)
print(School_bus.color, School_bus.name, "Speed:", School_bus.max_speed, "Mileage:", School_bus.mileage)
car = Car("Audi Q5", 240, 18)
print(car.color, car.name, "Speed:", car.max_speed, "Mileage:", car.mileage)
تمرین ۶. بررسی رابطه والد و فرزندی بین کلاس ها
کلاس والدی با نام Vehicle
و کلاس فرزندی با نام Bus
ایجاد کنید و درنهایت مشخص کنید آیا کلاس Bus
به عنوان کلاس فرزند برای کلاس Vehicle
محسوب میشود یا خیر؟
پاسخ تمرین ۶
جواب تمرین ۶ در ادامه ارائه شده است.
class Vehicle:
def __init__(self, name, mileage, capacity):
self.name = name
self.mileage = mileage
self.capacity = capacity
class Bus(Vehicle):
pass
School_bus = Bus("School Volvo", 12, 50)
# Python's built-in isinstance() function
print(isinstance(School_bus, Vehicle))
جمعبندی
شی گرایی یکی از مباحث مهم در برنامه نویسی است که پروژههای نرمافزاری بسیاری با استفاده از این رویکرد توسعه داده میشوند. بنابراین، یادگیری مفاهیم اصلی این رویکرد و پیادهسازی اجزا و اصول آن در برنامه به عنوان یکی از مهارتهای مهم و لازم برای برنامهنویسان به شمار میروند. در مطلب حاضر، سعی داشتیم به شی گرایی در پایتون بپردازیم و نحوه ساخت شی و کلاس را به عنوان عناصر مهم شی گرایی در این زبان در قالب مثال ارائه دهیم.
به علاوه، شی گرایی دارای چهار اصل مهم است که توسعه برنامههای مبتنی بر این رویکرد باید بر پایه این چهار اصل انجام شوند. در این مطلب، به چهار اصل مهم شی گرایی پرداخته و مفاهیم آنها با استفاده از مثالهای کاربردی در زبان پایتون ارائه شد.