شیءگرا (Object-Oriented Programming) به عنوان یکی از رویکردهای مهم در برنامهنویسی شناخته میشود. در شی گرایی به دادهها و عملیاتها به عنوان اشیاء نگریسته میشود. این رویکرد نه تنها به برنامهنویسان امکان میدهد که کدها را به شکل مرتب و ساختارمندی بنویسند بلکه از ویژگیهای شی گرایی نیز بهرهمند میشوند. شی گرایی در پایتون نیز پیاده سازی شده است.
پایتون (Python) به عنوان یکی از زبانهای برنامهنویسی محبوب، قابلیتهایی را برای پیادهسازی برنامهنویسی شیءگرا فراهم کرده است. در این مقاله، ما با مفاهیم برنامهنویسی شیءگرا آشنا میشویم و نحوه استفاده از آن در پایتون را بررسی میکنیم. پیشنهاد میکنیم از دیگر آموزشهای ما نیز دیدن فرمایید:
- لیست و نحوه کار با آن
- دیکشنری در پایتون
- Tuple در پایتون
- if در پایتون
- حلقه for
- حلقه while
- تابع در پایتون
- تبدیل نوع داده
مفاهیم پایه شی گرایی در پایتون
1. شیء (Object)
شیء، مفهوم اصلی در برنامهنویسی شیءگرا است. یک شیء میتواند یک نمونه (instance) از یک کلاس باشد و دارای ویژگیها و عملکردهای خود است. به عنوان مثال، اگر کلاسی به نام vehicle داشته باشیم، هر ماشین خاصی که از این کلاس ایجاد شود، یک شیء از نوع vehicle است.
2. کلاس (Class)
کلاس یک قالب برای ایجاد شیء میباشد. این کلاس تعیینکننده ویژگیها و عملکردهایی است که هر شیء از آن استفاده میکند. به عبارت دیگر، کلاس تعریف میکند که یک شیء از چه نوع دادهها و عملیاتهایی باید پشتیبانی کند. در پایتون، کلاسها با استفاده از کلمه کلیدی class تعریف میشوند.
3. ویژگیها (Attributes)
ویژگیها (یا متغیرها) دادههایی هستند که به هر شیء تعلق دارند و وضعیت آن را مشخص میکنند. این ویژگیها میتوانند از انواع مختلفی مثل عدد صحیح، رشته، یا حتی یک شیء دیگر باشند.
4. متدها (Methods)
متدها عملیاتهایی هستند که بر روی شیء انجام میدهند. آنها به کلاس مربوط به آن شیء مرتبط هستند و میتوانند به ویژگیها دسترسی داشته باشند. به عبارت دیگر، متدها تعیینکننده عملکرد یک شیء هستند.
5. ترکیب (Composition)
ترکیب به معنی ترکیب چندین شیء در یک شیء بزرگتر است. این رویکرد به ما این امکان را میدهد که شیءهای کوچکتر را با هم ترکیب کرده و شیءهای پیچیدهتری بسازیم. این مفهوم به ما این امکان را میدهد که کد را ماژولار و مدیریت کنیم.
6. وراثت (Inheritance)
وراثت به معنی ارثبری ویژگیها و متدهای یک کلاس به کلاسی دیگر است. این ویژگی به ما این امکان را میدهد که یک کلاس جدید را بر مبنای یک کلاس موجود تعریف کرده و ویژگیها و متدهای آن کلاس را به کلاس جدید ارث بری کنیم. این مفهوم به ما امکان مجدداً استفاده از کد و ایجاد ساختارهای سلسلهمراتبی از کلاسها را میدهد.
تعریف کلاس در پایتون
حال که با مفاهیم پایه شی گرایی در پایتون آشنا شدیم، به نگاهی به نحوه تعریف یک کلاس در پایتون میاندازیم. در پایتون، تعریف کلاس با استفاده از کلمه کلیدی class آغاز میشود. اسم کلاس باید با حرف بزرگ شروع شده و معمولاً با استفاده از نام اصلی کلاس تعیین میشود. به عنوان مثال، فرض کنید کلاسی به نام Person را تعریف کردهایم:
class Person:
pass
در این تعریف، کلمه class برای شروع تعریف کلاس استفاده شده است و نام کلاس به عنوان پسوند این تعریف آمده است. دستور pass به عنوان محتوای این کلاس است.
تعریف ویژگیها و متدها
بعد از تعریف کلاس، میتوانیم ویژگیها و متدهای آن کلاس را تعریف کنیم. ویژگیها، دادههایی هستند که به هر شیء از کلاس تعلق دارند و مقادیر متغیر را تعیین میکنند. متدها عملیاتهایی هستند که بر روی شیء انجام میدهند و عملکرد کلاس را تعیین میکنند.
class Person:
# ویژگیهای کلاس
def __init__(self, name, age):
self.name = name
self.age = age
# متد کلاس
def say_hello(self):
print(f"سلام، من {self.name} هستم و {self.age} سال دارم.")
در این تعریف کلاس Person، دو ویژگی به نام name و age با استفاده از متد __init__ تعریف شدهاند. متد __init__ به عنوان متد سازنده (constructor) شناخته میشود و هنگام ایجاد یک نمونه از کلاس اجرا میشود. متد say_hello نیز یک متد کلاس است که پیامی را به همراه اطلاعات ویژگیها نمایش میدهد.
ایجاد نمونه از کلاس
پس از تعریف کلاس، میتوانیم نمونهای از آن کلاس را ایجاد کنیم. این نمونه شیءی از کلاس است که میتوانیم با آن کار کنیم. برای ایجاد نمونه از کلاس، از نام کلاس به عنوان یک تابع استفاده میکنیم و پارامترهای مورد نیاز به متد سازنده (constructor) را به عنوان آرگومانها منتقل میکنیم.
# ایجاد نمونه از کلاس
person1 = Person("آرمان", 30)
person2 = Person("سارا", 25)
# فراخوانی متد شیء
person1.say_hello() # خروجی: "سلام، من آرمان هستم و 30 سال دارم."
person2.say_hello() # خروجی: "سلام، من سارا هستم و 25 سال دارم."
در این مثال، دو نمونه از کلاس Person با نامها و سنهای متفاوت ایجاد شدهاند و سپس متد say_hello بر روی هر دو نمونه فراخوانی شده است.
وراثت در شی گرایی
یکی از مفاهیم مهم در برنامهنویسی شیءگرا، وراثت (Inheritance) است. این مفهوم به ما این امکان را میدهد که یک کلاس جدید را بر مبنای یک کلاس موجود تعریف کرده و ویژگیها و متدهای آن کلاس را به کلاس جدید ارث بری کنیم.
برای تعریف یک کلاس جدید که از یک کلاس موجود ارث برده، نام کلاس جدید را تعریف کرده و نام کلاس والد (پدر) را به عنوان آرگومان به داخل پرانتز بنویسیم. به عنوان مثال، فرض کنید کلاس Employee به عنوان کلاس اصلی دارای ویژگیهایی مانند name و salary باشد:
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def display_info(self):
print(f"نام: {self.name}, حقوق: {self.salary}")
حالا میخواهیم یک کلاس به نام Manager تعریف کنیم که از کلاس Employee ارث برده و ویژگیها و متدهای آن کلاس را بهرهبرداری کند:
# ارث بری از کلاس Employee
class Manager(Employee):
def __init__(self, name, salary, department):
# فراخوانی متد سازنده کلاس مادر
super().__init__(name, salary)
self.department = department
def display_info(self):
print(f"نام: {self.name}, حقوق: {self.salary}, بخش: {self.department}")
در این مثال، کلاس Manager از کلاس Employee ارث برده و ویژگیها و متدهای مشترک با کلاس والد را دارد. همچنین، متد display_info را بازنویسی کردهایم تا اطلاعات بیشتری را نمایش دهد.
تعیین وراثت و چندریختی (polymorphism)
وراثت یکی از مفاهیم مهم شی گرایی در پایتون است که به ما امکان مجدداً استفاده از کد و ایجاد ساختارهای سلسلهمراتبی از کلاسها را میدهد. از طرفی، پلیمورفیسم (Polymorphism) نیز یکی دیگر از مفاهیم اساسی این رویکرد است که به ما امکان انجام عملیاتهای یکسان بر روی اشیاء مختلف را میدهد.
پلیمورفیسم به معنی این است که شیءهای مختلف میتوانند به یک متد یا تابع به شکل متفاوت پاسخ دهند. به عبارت دیگر، اگر چند کلاس از یک متد یا تابع استفاده کنند، هر یک میتوانند عملیات مختلفی انجام دهند. این امکان به ما اجازه میدهد که با استفاده از کد یکسان عملیاتهای مختلفی را انجام دهیم.
برای مثال، در پایتون، میتوانیم از پلیمورفیسم بهرهبرداری کنیم و یک تابع را بر روی اشیاء مختلف اجرا کنیم. به عنوان مثال، فرض کنید دو کلاس به نام Circle و Rectangle داشته باشیم، هر یک با متدهای مخصوص به خود:
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
حالا میتوانیم یک تابع به نام calculate_area تعریف کنیم که بر روی اشیاء این دو کلاس عملیات محاسبه مساحت را انجام دهد:
def calculate_area(shape):
return shape.area()
# ایجاد شیء از کلاس Circle
circle = Circle(5)
# ایجاد شیء از کلاس Rectangle
rectangle = Rectangle(4, 6)
# فراخوانی تابع calculate_area بر روی اشیاء
print("مساحت دایره:", calculate_area(circle)) # خروجی: "مساحت دایره: 78.5"
print("مساحت مستطیل:", calculate_area(rectangle)) # خروجی: "مساحت مستطیل: 24"
در این مثال، تابع calculate_area به عنوان ورودی یک شیء از یک کلاس میپذیرد و متد area آن شیء را فراخوانی میکند تا مساحت آن را محاسبه کند. به این ترتیب، میتوانیم همان تابع را بر روی اشیاء مختلف اعمال کنیم و مساحت را محاسبه کنیم.