وراثت و مفهوم پیشرفته شی گرایی
وراثت و مفاهیم پیشرفته شی گرایی تا اینجا یاد گرفتهاید که چگونه با استفاده از کلاس (Class) و شی (Object)
تا اینجا یاد گرفتهاید که چگونه با استفاده از کلاس (Class) و شی (Object) برنامههای خود را ساختارمندتر کنید. اما در پروژههای واقعی معمولاً کلاسهایی وجود دارند که ویژگیها و رفتارهای مشترک زیادی دارند. در اینصورت آیا باید تمام این کدها را دوباره بنویسیم؟
خوشبختانه اینطور نیست. پایتون قابلیتی به نام وراثت (Inheritance) دارد که به ما اجازه میدهد یک کلاس جدید را بر اساس یک کلاس دیگر ایجاد کنیم. در این حالت کلاس جدید تمام ویژگیها و متدهای کلاس قبلی را به ارث میبرد و در صورت نیاز میتواند قابلیتهای جدیدی نیز به آن اضافه کند.
به کمک وراثت:
فرض کنید در حال طراحی یک نرمافزار مدرسه هستید. تمام افراد مدرسه دارای اطلاعات مشترکی هستند:
اما هر گروه ویژگیهای مخصوص خود را نیز دارد. مثلا گروه دانشآموزان دارای اطلاعاتی مانند پایه تحصیلی و معدل هستند. در صورتیکه گروه معلمان دارای اطلاعات دیگری مانند رشته تدریس و حقوق هستند.
اگر بخواهیم برای هرکدام یک کلاس جداگانه بنویسیم، مجبور میشویم اطلاعات مشترک را چندین بار تکرار کنیم.
مثلاً:
class Student:
name
age
national_id
grade
average
class Teacher:
name
age
national_id
subject
salaryمشاهده میکنید که سه ویژگی اول در هر دو کلاس تکرار شدهاند. در اینجا ما باید از وراثت استفاده کنیم.
ابتدا یک کلاس کلی به نام Person میسازیم. تمام ویژگیهای مشترک را داخل آن قرار میدهیم. سپس کلاسهای Student و Teacher را از روی آن ایجاد میکنیم.
Person
/ \
Student Teacherدر این حالت:
به همین دلیل به Person میگوییم کلاس والد (Parent Class) و به Student و Teacher میگوییم کلاس فرزند (Child Class)
نوشتن وراثت در پایتون بسیار ساده است. کافی است نام کلاس والد را داخل پرانتز بنویسیم.
class Parent:
pass
class Child(Parent):
passاکنون کلاس Child تمام اعضای Parent را در اختیار دارد.
فرض کنید یک کلاس برای حیوانات داریم.
class Animal:
def speak(self):
print("Animal is speaking")اکنون یک کلاس جدید ایجاد میکنیم.
class Dog(Animal):
passو یک شی از آن میسازیم.
dog = Dog()
dog.speak()خروجی:
Animal is speakingتوجه کنید که متد speak() داخل کلاس Dog نوشته نشده است، اما چون Dog از Animal ارث برده، به این متد دسترسی دارد.
وقتی یک کلاس از کلاس دیگری ارث میبرد، تقریباً همه اعضای عمومی آن را در اختیار خواهد داشت، از جمله:
__init__) (در شرایطی که در کلاس فرزند بازنویسی نشده باشد)به همین دلیل، کلاس فرزند میتواند بدون نوشتن مجدد کد، از قابلیتهای کلاس والد استفاده کند.
در مثالهای قبلی دیدیم که کلاس فرزند میتواند متدهای کلاس والد را به ارث ببرد. اما در پروژههای واقعی، کلاسها معمولاً دارای سازنده (__init__) هستند تا هنگام ایجاد شی، اطلاعات اولیه را دریافت و ذخیره کنند. بیایید یک مثال واقعی را بررسی کنیم.
ابتدا یک کلاس به نام Person میسازیم.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print("Name:", self.name)
print("Age:", self.age)این کلاس دو ویژگی دارد: name و age و یک متد برای نمایش اطلاعات.
اکنون میخواهیم کلاس Student را از روی Person ایجاد کنیم.
class Student(Person):
passدر نگاه اول شاید تصور کنید این کلاس هیچ کاری انجام نمیدهد، اما چون از Person ارث برده است، تمام اعضای آن را در اختیار دارد. حال یک شی ایجاد میکنیم.
student = Student("Ali", 18)
student.show_info()خروجی:
Name: Ali
Age: 18دقت کنید که کلاس Student هیچ متدی ندارد، اما چون از Person ارث برده است، هم سازنده (__init__) و هم متد show_info() را در اختیار دارد.
زمانی که این دستور اجرا میشود:
student = Student("Ali", 18)پایتون ابتدا بررسی میکند که آیا کلاس Student دارای متد __init__ است یا خیر. از آنجا که چنین متدی وجود ندارد، به کلاس والد یعنی Person مراجعه میکند و سازندهی آن را اجرا میکند. به همین دلیل مقادیر name و age بهدرستی مقداردهی میشوند.
فرض کنید بخواهیم هر دانشآموز علاوه بر نام و سن، دارای یک پایه تحصیلی نیز باشد. اکنون کلاس فرزند باید علاوه بر ویژگیهای والد، ویژگی جدیدی نیز داشته باشد. در نگاه اول ممکن است فکر کنیم که چنین کدی باید بنویسیم:
class Student(Person):
def __init__(self, name, age, grade):
self.grade = gradeاما این کد یک مشکل بزرگ دارد. آنهم این است که ویژگیهای name و age دیگر مقداردهی نمیشوند، زیرا با تعریف سازنده جدید، سازنده کلاس والد اجرا نخواهد شد.
در بخش قبل دیدیم که اگر کلاس فرزند دارای متد __init__ باشد، سازنده کلاس والد بهصورت خودکار اجرا نمیشود. در چنین شرایطی باید خودمان سازنده کلاس والد را فراخوانی کنیم. پایتون برای این کار تابع بسیار کاربردی super() را در اختیار ما قرار داده است. به کمک super() میتوانیم به اعضای کلاس والد دسترسی داشته باشیم و از آنها استفاده کنیم.
super()کلاس والد Person را دوباره در نظر بگیرید.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def show_info(self):
print("Name:", self.name)
print("Age:", self.age)اکنون کلاس دانشآموز را مینویسیم.
class Student(Person):
def __init__(self, name, age, grade):
super().__init__(name, age)
self.grade = gradeبه این خط دقت کنید.
super().__init__(name, age)این دستور باعث میشود سازنده کلاس Person اجرا شود و ویژگیهای name و age مقداردهی شوند. سپس ویژگی جدید grade نیز به کلاس فرزند اضافه میشود.
student = Student("Ali", 18, 12)
student.show_info()
print("Grade:", student.grade)خروجی:
Name: Ali
Age: 18
Grade: 12super() استفاده میکنیم؟فرض کنید کلاس والد دارای ۱۰ ویژگی باشد. اگر از super() استفاده نکنیم، مجبور هستیم تمام آنها را دوباره در کلاس فرزند بنویسیم.
مثلاً:
self.name = name
self.age = age
self.address = address
self.phone = phone
...این کار چند مشکل ایجاد میکند:
اما با یک خط کد:
super().__init__(...)تمام این مقداردهیها توسط کلاس والد انجام میشوند.
فرض کنید در یک شرکت اطلاعات تمام کارکنان در کلاس Employee ذخیره میشود.
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salaryاکنون میخواهیم کلاس برنامهنویس را ایجاد کنیم.
class Programmer(Employee):
def __init__(self, name, salary, language):
super().__init__(name, salary)
self.language = languageایجاد شی:
programmer = Programmer(
"Sara",
80000,
"Python"
)
print(programmer.name)
print(programmer.salary)
print(programmer.language)خروجی:
Sara
80000
Python
استفاده از super() فقط به سازنده (__init__) محدود نیست. با استفاده از آن میتوان هر متدی از کلاس والد را نیز فراخوانی کرد. این موضوع زمانی اهمیت پیدا میکند که بخواهیم متدی را در کلاس فرزند تغییر دهیم اما همچنان بخشی از رفتار کلاس والد را حفظ کنیم. این مفهوم را بازنویسی متدها (Method Overriding) مینامند که در بخش بعدی با مثالهای کاربردی آن آشنا خواهیم شد.
گاهی اوقات کلاس فرزند میخواهد یکی از متدهای کلاس والد را به شکل متفاوتی اجرا کند. در این حالت همان متد را دوباره داخل کلاس فرزند مینویسیم. به این کار بازنویسی متد یا Method Overriding گفته میشود.
به بیان ساده کلاس فرزند میتواند رفتار یک متد را تغییر دهد، بدون اینکه سایر قابلیتهای کلاس والد را از دست بدهد.
فرض کنید کلاس والد دارای متدی برای تولید صدا باشد.
class Animal:
def speak(self):
print("Some animal sound")حالا کلاس سگ را ایجاد میکنیم.
class Dog(Animal):
def speak(self):
print("Woof Woof")و سپس:
dog = Dog()
dog.speak()خروجی:
Woof Woofکلاس Dog متدی با همان نام speak() ایجاد کرده است. بنابراین زمانی که این دستور اجرا میشود:
dog.speak()پایتون ابتدا کلاس Dog را بررسی میکند. چون متد موردنظر در کلاس فرزند وجود دارد، دیگر به کلاس والد مراجعه نمیکند. به همین دلیل خروجی "Woof Woof" نمایش داده میشود.
class Bird:
def move(self):
print("Bird is moving")کلاس فرزند:
class Eagle(Bird):
def move(self):
print("Eagle is flying")اجرای برنامه:
eagle = Eagle()
eagle.move()خروجی:
Eagle is flyingمتد کلاس والد همچنان وجود دارد، اما زمانی که همان متد در کلاس فرزند تعریف شود، نسخهی کلاس فرزند اجرا خواهد شد. در واقع، کلاس فرزند متد والد را جایگزین میکند، نه اینکه آن را حذف کند.
گاهی اوقات نمیخواهیم متد کلاس والد را کاملاً حذف کنیم. بلکه میخواهیم ابتدا کارهای کلاس والد انجام شود و سپس قابلیتهای جدیدی اضافه کنیم. در اینجا دوباره super() به کمک ما میآید.
class Animal:
def speak(self):
print("Animal makes a sound")کلاس فرزند:
class Dog(Animal):
def speak(self):
super().speak()
print("Dog says Woof")اجرای برنامه:
dog = Dog()
dog.speak()خروجی:
Animal makes a sound
Dog says Woofمزیت این روش این است که ابتدا رفتار اصلی کلاس والد اجرا میشود. سپس رفتار اختصاصی کلاس فرزند اضافه میشود. به همین دلیل دیگر نیازی نیست کدهای کلاس والد را دوباره بنویسیم.
فرض کنید در حال طراحی یک فروشگاه اینترنتی هستیم. تمام محصولات دارای یک متد برای نمایش اطلاعات هستند.
class Product:
def show_info(self):
print("Product Information")اکنون کلاس لپتاپ را ایجاد میکنیم.
class Laptop(Product):
def show_info(self):
super().show_info()
print("Category: Laptop")
print("Brand: Lenovo")اجرای برنامه:
laptop = Laptop()
laptop.show_info()خروجی:
Product Information
Category: Laptop
Brand: Lenovoدر این مثال، اطلاعات عمومی محصول توسط کلاس والد نمایش داده میشود و سپس اطلاعات اختصاصی لپتاپ توسط کلاس فرزند اضافه میشود.
بازنویسی متدها زمانی کاربرد دارد که کلاس فرزند بخواهد رفتار یک متد را متناسب با نیاز خود تغییر دهد، بدون اینکه ساختار کلی کلاس والد را از بین ببرد. از این قابلیت در موارد زیر بسیار استفاده میشود:
Method Overriding با Method Overloading متفاوت است. در زبانهایی مانند Java یا C++ میتوان چند متد با یک نام ولی پارامترهای متفاوت تعریف کرد که به آن Overloading گفته میشود. اما در پایتون، مفهوم Overloading به آن شکل پشتیبانی نمیشود و بیشتر با استفاده از پارامترهای پیشفرض (default arguments) یا آرگومانهای متغیر (*args و **kwargs) پیادهسازی میشود.
کلمه Polymorphism از دو واژه یونانی تشکیل شده است: Poly یعنی چند و Morph یعنی شکل
بنابراین Polymorphism به معنای چندشکلی یا چندریختی است. در برنامهنویسی، چندریختی یعنی چند کلاس مختلف میتوانند متدی با نام یکسان داشته باشند، اما هر کدام آن متد را به روش مخصوص خود اجرا کنند.
فرض کنید سه حیوان داریم. همه آنها میتوانند صدا تولید کنند، اما صدای هر کدام متفاوت است.
class Dog:
def speak(self):
print("Woof")class Cat:
def speak(self):
print("Meow")class Cow:
def speak(self):
print("Moo")هر سه کلاس دارای متدی به نام speak() هستند. اما خروجی آنها متفاوت است.
اکنون تابعی مینویسیم که نوع حیوان برایش مهم نباشد.
def animal_sound(animal):
animal.speak()حالا:
dog = Dog()
cat = Cat()
cow = Cow()
animal_sound(dog)
animal_sound(cat)
animal_sound(cow)خروجی:
Woof
Meow
Mooتوجه کنیدکه تابع animal_sound() فقط یک دستور دارد:
animal.speak()اما بسته به اینکه شیء از چه کلاسی باشد، خروجی تغییر میکند. اگر شیء از کلاس Dog باشد:
Woofاگر از کلاس Cat باشد:
Meowو اگر از کلاس Cow باشد:
Mooدر واقع، یک متد با یک نام ثابت وجود دارد، اما رفتار آن برای هر کلاس متفاوت است.
فرض کنید در حال طراحی نرمافزار پرداخت هستیم. روشهای پرداخت مختلفی وجود دارند. همه دارای متدی به نام pay() هستند.
class CreditCard:
def pay(self):
print("Paid with credit card")class BankTransfer:
def pay(self):
print("Paid by bank transfer")class Cash:
def pay(self):
print("Paid with cash")تابع پرداخت:
def process_payment(method):
method.pay()استفاده:
process_payment(CreditCard())
process_payment(BankTransfer())
process_payment(Cash())خروجی:
Paid with credit card
Paid by bank transfer
Paid with cash
نکته مهم این است که چندریختی همیشه به وراثت وابسته نیست. در پایتون اگر چند شیء متدی با نام یکسان داشته باشند، میتوان از آنها بهصورت چندریختی استفاده کرد. به این ویژگی Duck Typing گفته میشود. اما در پروژههای شیگرا، معمولاً چندریختی همراه با وراثت استفاده میشود.
مثلاً:
class Animal:
def speak(self):
print("Animal sound")class Dog(Animal):
def speak(self):
print("Woof")class Cat(Animal):
def speak(self):
print("Meow")اکنون:
animals = [
Dog(),
Cat()
]
for animal in animals:
animal.speak()خروجی:
Woof
Meowدر این مثال، متغیر animal در هر بار اجرای حلقه به شیئی از کلاس متفاوت اشاره میکند، اما برنامه بدون هیچ شرط (if یا elif) متد مناسب را اجرا میکند.
استفاده از چندریختی باعث میشود:
if و elif) کاهش یابد.super() استفاده کنید.
show_info() ایجاد کنید و اطلاعات هر محصول را نمایش دهید.
move()
داخل آن قرار دهید که پیام:
Vehicle is moving
را چاپ کند.
سپس سه کلاس فرزند ایجاد کنید:
move() را در هر کلاس بازنویسی کنید تا حرکت مخصوص خود را نمایش دهد.
pay()
داشته باشد.
سپس یک لیست از روشهای پرداخت ایجاد کنید و با استفاده از یک حلقه، متد pay() هر شیء را اجرا کنید.
هدف تمرین: پیادهسازی مفهوم Polymorphism بدون استفاده از شرطها.
introduce()
ایجاد کنید و آن را در کلاسهای فرزند بازنویسی کنید.
در پایان، چند شیء از دانشآموز و معلم بسازید و اطلاعات آنها را نمایش دهید.
کپسولهسازی (Encapsulation) یکی از اصول مهم شیگرایی است که به ما کمک میکند دسترسی به ویژگیها و متدهای یک کلاس را کنترل کنیم. با استفاده از این مفهوم، میتوانیم مشخص کنیم کدام اطلاعات بهصورت عمومی در دسترس باشند و کدام بخشها فقط از داخل خود کلاس قابل استفاده باشند.
گام بعدی : کپسوله سازیوراثت و مفاهیم پیشرفته شی گرایی تا اینجا یاد گرفتهاید که چگونه با استفاده از کلاس (Class) و شی (Object)
کلاس و شیء در پایتون (Object-Oriented Programming) تا اینجا با متغیرها، شرطها، حلقهها، توابع و ساختارهای داده در پایتون آشنا
تابع لامبدا (Lambda Function) در پایتون گاهی اوقات فقط به یک تابع خیلی کوچک نیاز داریم؛ تابعی که قرار است
توابع در پایتون اگر هنگام برنامهنویسی مجبور شوید یک قطعه کد را بارها تکرار کنید، برنامه شما طولانی، شلوغ و
مجموعه (Set) در پایتون به زبان ساده، Set مجموعهای از عناصر منحصربهفرد (Unique) است که ترتیب مشخصی ندارد و اجازه
دیکشنری در پایتون تا اینجا با لیست (List) و تاپل (Tuple) آشنا شدیم که هر دو مجموعهای از دادهها را
تاپل (Tuple) در پایتون بعد از آشنایی با لیست (List)، نوبت به یکی دیگر از ساختارهای داده در پایتون یعنی
لیست (List) در پایتون پرکاربردترین ساختار داده تا اینجا یاد گرفتید که هر متغیر فقط یک مقدار را در خود
ساختارهای داده در پایتون در برنامههای واقعی معمولاً با یک داده سروکار نداریم، بلکه باید تعداد زیادی اطلاعات را ذخیره
حلقههای تکرار در پایتون (Python Loops) فرض کنید معلم میخواهد نمرات ۳۰ دانشآموز را از کاربر دریافت کند. اگر حلقه
عملگرهای مقایسهای (Comparison Operators) تا اینجا یاد گرفتیم که با عملگرهای محاسباتی میتوانیم اعداد را با هم جمع، تفریق و…
دریافت ورودی از کاربر در پایتون (Python Input) تا اینجا یاد گرفتیم که چگونه مقدار یک متغیر را خودمان داخل
عملگرهای محاسباتی در پایتون (Arithmetic Operators) تقریباً تمام برنامهها به انجام محاسبات نیاز دارند؛ از جمع و تفریق ساده گرفته
کار با رشتهها در پایتون (Python Strings) مدیریت و پردازش متنها در برنامهها در دنیای برنامهنویسی، اطلاعات همیشه عدد و
متغیرها در پایتون (Python Variables) اولین قدم برای ذخیره و پردازش اطلاعات تصور کنید یک برنامه مینویسید که قرار است
شروع برنامه نویسی با پایتون ساخت اولین پروژه (Hello World) فهرست مطالب بعد از نصب Python چه کاری انجام دهیم؟
آموزش نصب پایتون و ابزارهای موردنیاز (راهنمای کامل برای ویندوز) اگر تصمیم گرفتهاید برنامهنویسی را یاد بگیرید، احتمالاً نام زبان
الگوهای کندل استیک پیشرفته: راهنمای جامع برای معاملهگران حرفهای الگو های کندل استیک پیشرفته (یا به بیان دیگر الگوهای شمعی
آیلتس جنرال یا آکادمیک؟ کدام را باید انتخاب کنیم؟ آیا میدانید که انتخاب اشتباه بین آیلتس آکادمیک و جنرال میتواند
دانلود رایگان نمونه سوالات آزمون PTE جنرال اگر تصمیم گرفتهاید با هدف مهاجرت به یک کشور انگلیسی زبان، در آزمون
معرفی آزمون های زبان انگلیسی معتبر در ایران| کدام یک بهتر است؟ اگه قصد ادامه تحصیل یا مهاجرت داشته باشید،
بهترین روشهای آمادگی برای آزمون تافل چگونه برای آزمون تافل آماده شویم؟ آیا شما هم قصد دارید برای کسب نمره
چگونه در خارج از کشور برای آزمون آیلتس ثبت نام کنیم؟ اگر قصد مهاجرت تحصیلی یا کاری دارید، احتمالاً نام
آزمون GRE مناسب چه رشتههایی است؟ اگر قصد ادامه تحصیل در مقاطع کارشناسی ارشد یا دکترا در دانشگاههای بینالمللی را
بهترین نمونه سوالات اسپیکینگ تافل هوم ادیشن آزمون تافل هوم ادیشن این روزها یکی از پرطرفدارترین گزینهها برای سنجش مهارت
نحوه ثبت نام در آزمون دولینگو در ایران به صورت کامل نحوه ثبت نام در آزمون دولینگو در ایران چگونه
هزینه آزمون GRE در ایران چقدر است؟ اگر قصد مهاجرت تحصیلی دارید، احتمالاً نام آزمون GRE به گوشتان خورده است.
راهنمای کامل ثبتنام و پرداخت هزینه آزمون PTE در ترکیه برای متقاضیان ایرانی آزمون PTE (Pearson Test of English) یکی از
ووچر آزمون چیست و چگونه میتوان آن را تهیه کرد؟ ثبتنام در آزمونهای بینالمللی مانند TOEFL، GRE، PTE، GMAT، IELTS
بهترین تکنیک های لیسنینگ آیلتس برای کسب نمره بالا آزمون آیلتس (IELTS) یکی از معتبرترین آزمونهای ارزیابی مهارت زبان انگلیسی
آزمون پلاس مرجع آموزش برنامهنویسی، هوش مصنوعی، شبکه، نمونه سؤالات کنکورهای کامپیوتر، آزمونهای زبان دکتری و مدارک بینالمللی فناوری اطلاعات است. با ارائه آموزشهای تخصصی، منابع آموزشی و راهنمای آزمونها، به دانشجویان و متخصصان کمک میکنیم تا مهارتهای خود را توسعه داده و در مسیر موفقیت تحصیلی و شغلی گام بردارند.