🚀 فصل ۱۱: شی‌گرایی (Object-Oriented Programming) در پایتون

""

۱۱.۱ | شی‌گرایی یعنی چی؟ (مقدمه‌ای ساده)

برنامه‌نویسی شی‌گرا روشی برای نگهداری و مدیریت کد است که همه‌چیز حول محور “اشیاء” (Object) سازماندهی می‌شود، نه فقط توابع و متغیرها.

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

  • ویژگی‌ها (attributes – داده‌های شی)
  • رفتارها (methods – کارهایی که شی می‌تونه انجام بده – در واقع همون تابع داخل شی)

۱۱.۲ | کلاس و شی چیست؟ تفاوت کلاس و شی

  • کلاس (class): قالب یا نقشه برای ساختن شی‌هاست.
  • شی (object): نمونه‌ی واقعی ساخته‌شده از یک کلاس.

مثال ساده:

کلاس = نقشه‌ی یک خانه
شی = یک خانه واقعی که روی زمین ساخته شده


۱۱.۳ | چگونه کلاس بسازیم؟

تعریف یک کلاس ساده:

class Car:
    pass   # وقتی هنوز نمی‌خواید چیزی داخل کلاس بنویسید (کلمه ی pass یعنی هیچ کاری نکن!)

ساختن یک شی از روی کلاس:

my_car = Car()
print(type(my_car))

خروجی:

<class '__main__.Car'>

۱۱.۴ | سازنده کلاس – متد init

وقتی یک شی ساخته می‌شود، متد مخصوص به نام __init__ (سازنده) خودش اتومات صدا زده میشه تا ویژگی‌های اولیه رو بده.

مثال:

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

my_dog = Dog("ماکسی", 3)
print(my_dog.name)   # خروجی: ماکسی
print(my_dog.age)    # خروجی: 3

هر متدی که تو کلاس تعریف می‌کنی باید اولین پارامترش self باشه (به خودش یعنی شی فعلی اشاره می‌کنه).


۱۱.۵ | ویژگی‌ها (attributes) و رفتارها (methods)

اضافه کردن ویژگی (Attribute)

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

my_book = Book("شازده کوچولو", "اکسیوپری")
print(my_book.title)    # خروجی: شازده کوچولو

تعریف رفتار یا متد (Method)

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def show_info(self):
        print(f"{self.title} نوشته‌ی {self.author}")

b = Book("شازده کوچولو", "اکسیوپری")
b.show_info()   # خروجی: شازده کوچولو نوشته‌ی اکسیوپری

۱۱.۶ | تفاوت ویژگی‌های نمونه و ویژگی‌های کلاس

  • ویژگی نمونه (Instance Attribute): وابسته به هر شی (self)
  • ویژگی کلاس (Class Attribute): مشترک برای همه اشیا (خارج از def init)

مثال:

class Cat:
    species = "پستاندار"      # ویژگی کلاس

    def __init__(self, name):
        self.name = name     # ویژگی نمونه

cat1 = Cat("سیاه")
cat2 = Cat("سفید")
print(cat1.species)      # خروجی: پستاندار
print(cat2.species)      # خروجی: پستاندار
print(cat1.name)         # خروجی: سیاه
print(cat2.name)         # خروجی: سفید

۱۱.۷ | متدهای ویژه (Special Methods) – مانند str

  • متد __str__ روش چاپ شی رو تعیین می‌کنه:
class Book:
    def __init__(self, title):
        self.title = title
    def __str__(self):
        return f"کتاب: {self.title}"

b = Book("کیمیاگر")
print(b)    # خروجی: کتاب: کیمیاگر

۱۱.۸ | وراثت (Inheritance) – استفاده از قابلیت یک کلاس در کلاس دیگر

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

مثال:

class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        print("صدا ندارد!")

class Cat(Animal):
    def speak(self):
        print("میو میو")

cat = Cat("ملوس")
cat.speak()  # خروجی: میو میو

کلاس Cat هم ویژگی name رو داره (از Animal به ارث برده)، هم متد speak رو بازنویسی (override) کرده.


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


کپسوله‌سازی (Encapsulation) در پایتون: راهنمای کامل و کاربردی


💡 کپسوله‌سازی یعنی چی؟

کپسوله‌سازی (Encapsulation) یعنی:

  • مخفی کردن جزئیات داخلی شی (کلاس) تا هر کسی نتونه از بیرون به داده‌ها (متغیرها) و متدهای داخلی دسترسی مستقیم داشته باشه.
  • به زبان ساده یعنی یک “پوسته” دور داده‌ها و توابع کلاس می‌کشی تا کنترل کنی چه کسی و چطور بهشون دسترسی داشته باشه.

این کار باعث:

  • امنیت بیشتر (اطلاعات مهم مثل پسورد، موجودی بانک و …)
  • جلوگیری از بهم‌ریختگی و اشتباهات ناخواسته
  • امکان تغییر دیتای داخلی بدون نگرانی برای دیگران
  • سادگی در استفاده (دیگران می‌فهمن چه چیزی در دسترسِشونه، چه چیزی نه)

📦 چطور در پایتون کپسوله‌سازی کنیم؟

در برخی زبان‌ها مثل Java یا C# کلمه کلیدی داریم مثل private یا public.
اما در پایتون راهش فرق داره:
اینجا روی فرهنگ برنامه‌نویسی و نشانه‌گذاری (Name Mangling) حساب میشه، نه اجبار سختگیرانه.

سه حالت برای متغیرهای کلاس:

  1. عمومی (Public): همه جا قابل دسترس
    python self.name = value
  2. محافظت‌شده (Protected): توصیه میشه فقط در خود کلاس و زیرکلاس‌ها استفاده بشه
    python self._age = value
  3. خصوصی (Private): فقط داخل خود کلاس
    python self.__balance = value

۱. حالت عمومی (Public)

class Person:
    def __init__(self, name):
        self.name = name   # عمومی

p = Person("علی")
print(p.name)    # بله! دسترسی داریم

۲. حالت محافظت‌شده (Protected) با یک آندرلاین

قانونی نیست که کسی نتونه دسترسی پیدا کنه؛ فقط یک «لطفا دست نزن» حرفه‌ایه!

class Person:
    def __init__(self, name):
        self._name = name  # محافظت‌شده (نه خصوصی!)

p = Person("علی")
print(p._name)   # قابل دسترسی، ولی توصیه نمیشه

۳. حالت خصوصی (Private) با دو آندرلاین

پایتون خودش اسم متغیر رو تغییر میده! این یعنی دسترسی مستقیم سخت‌تر (اما باز هم هک‌شدنیه).

class Person:
    def __init__(self, name):
        self.__name = name   # خصوصی

p = Person("علی")
# print(p.__name)         # خطا -> AttributeError

اگر سعی کنی مستقیم دسترسی پیدا کنی خطا می‌گیری، اما:

print(p._Person__name)      # بهش دسترسی داری! اما اصلاً توصیه نمیشه

این مکانیزم رو Name Mangling می‌گن.


✨ چرا کپسوله‌سازی؟ با مثال واقعی

فرض کن حساب بانکی داری و مقدار موجودی داخلش هست:

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount

    def withdraw(self, amount):
        if amount > 0 and amount <= self.__balance:
            self.__balance -= amount

    def get_balance(self):
        return self.__balance

از بیرون، معلوم نیست موجودی حساب چقدره و کسی مستقیماً نمیتونه تغییرش بده:

acc = BankAccount(1000)
acc.deposit(500)
print(acc.get_balance())   # 1500

acc.__balance = 1_000_000    #!!! فکر می‌کنیم مقدار تغییر کرد، اما واقعاً نه!
print(acc.get_balance())     # هنوز همون مقدار اصلی (1500)

print(acc.__dict__)          
# خروجی می‌بینی که __balance واقعاً عوض نشده؛ یه متغیر جدید با این اسم ساخته شد!

🛡️ دسترسی‌ها را کنترل کن: Getter و Setter

بهترین روش اینه که دسترسی به اطلاعات رو فقط از طریق “متدهای کنترل شده” (getter و setter) فراهم کنی.

نمونه ساده:

class Student:
    def __init__(self, score):
        self.__score = score

    def get_score(self):        # Getter
        return self.__score

    def set_score(self, value): # Setter
        if 0 <= value <= 20:
            self.__score = value
        else:
            print("نمره نامعتبر است!")

stu = Student(17)
print(stu.get_score())

stu.set_score(21)      # نمره نامعتبر است!
print(stu.get_score()) # 17

🏷️ property: کپسول‌سازی پیشرفته و شیواتر

پایتون راهی شیک داره:
میتونی با دکوریتور @property متد getter و setter بسازی و استفاده ازش درست مثل یک ویژگی عادی باشه!

class Product:
    def __init__(self, price):
        self.__price = price

    @property
    def price(self):                   # Getter
        return self.__price

    @price.setter
    def price(self, value):            # Setter
        if value >= 0:
            self.__price = value
        else:
            print("قیمت نمی‌تونه منفی باشه!")

p = Product(250)
print(p.price)    # مثل ویژگی عادی

p.price = -5      # قیمت نمی‌تونه منفی باشه!
print(p.price)    # 250

خاصیت property باعث میشه بدون اینکه درگیر متد بشی، انگار با یک متغیر معمولی کار کنی اما پشت پرده همه‌چیز حرفه‌ای و امن بمونه!


🚦 کپسوله‌سازی و وراثت: در عمل چه اتفاقی می‌افتد؟

اگر متغیری خصوصی تعریف کردی (__var)، در زیرکلاس (SubClass) بهش دسترسی نداری! اما متغیر محافظت‌شده (_var) در زیرکلاس قابل استفاده‌ست.

مثال:

class Parent:
    def __init__(self):
        self._protected = "yes"
        self.__private = "نه"

class Child(Parent):
    def show(self):
        print(self._protected)       # اوکی
        # print(self.__private)     # خطا میده

c = Child()
c.show()

📝 نکته‌های حرفه‌ای کپسوله‌سازی در پایتون

  • استفاده از دو آندرلاین واقعاً حالت خصوصی می‌سازه، اما هکر یا برنامه‌نویس پیشرفته در مواقع خاص باز هم راه‌هایی داره.
  • Propertyها رو برای خواناتر کردن کد، ساده‌تر کردن و کنترل بهتر توصیه اکید می‌کنم.
  • قوانین کپسوله‌سازی و “عدم دسترسی” اخلاقی‌تر از فنی است (Python به تو اعتماد دارد ولی انتظار دارد اشتباه نکنی!).
  • بهترین راه: “دسترسی فقط از طریق متد!”

💪 جمع‌بندی: چراEncapsulation مهم است؟

  • ساختار کد را تمیزتر نگه می‌دارد
  • امنیت داده‌های حساس را بیشتر می‌کند
  • کد قابل تغییرتر (Maintainable) و قابل گسترش‌تر می‌شود
  • اشتباهات ناخواسته را کاهش می‌دهد
  • برای پروژه‌های تیمی و سیستم‌های بزرگ حیاتی است

تمرین سریع

۱. یک کلاس بساز که مقدار نمره (0 تا 100) را فقط با property قابل تغییر کند و اگر کسی عدد اشتباهی داد، خطا نمایش دهد.
۲. تست کن: اگر کسی از بیرون بخواهد مقدار خصوصی را عوض کند، چه اتفاقی می‌افتد؟


۱۱.۱۰ | چندشکلی (Polymorphism) و متد override

  • چندشکلی = یک متد می‌تونه اعمال مختلف بر کلاس‌های مختلف انجام بده.
  • override = بازنویسی یک متد که از کلاس پدر به ارث برده‌اید.

مثال ساده:

class Animal:
    def speak(self):
        print("صدا ندارد!")

class Dog(Animal):
    def speak(self):
        print("هاپ هاپ")

class Cat(Animal):
    def speak(self):
        print("میو میو")

animals = [Dog(), Cat(), Animal()]
for a in animals:
    a.speak()
# خروجی:
# هاپ هاپ
# میو میو
# صدا ندارد!

۱۱.۱۱ | جمع‌بندی سریع با جدول

اصطلاحمعنی و مثال کوتاه
کلاس (Class)قالب یا نقشه ساخت اشیا (class Car:)
شی (Object)نمونه از کلاس (my_car = Car())
ویژگی (Attribute)داده‌های هر شی (self.name = name)
متد (Method)رفتاری که شی می‌تواند انجام دهد (def drive(self))
وراثت (Inheritance)استفاده از یک کلاس دیگر (class Cat(Animal))
کپسوله‌سازی (Encapsulation)مخفی‌کردن داده (متغیر خصوصی)
چندشکلی (Polymorphism)یک متد چند رفتار مختلف دارد

۱۱.۱۲ | تمرینات ساده و کاربردی (OOP)

۱. کلاسی به اسم Student بساز که نام، سن و نمره داشته باشد و یک متد show_info نمایش اطلاعات بنویسد.
۲. کلاسی به اسم Circle بساز که شعاع را بگیرد، متدی برای محاسبه مساحت و محیط دایره بنویسد (فرمول: مساحت=πr^2، محیط=2πr).
۳. وراثت ایجاد کن: کلاس Vehicle (خودرو)، کلاس Car از Vehicle ارث ببرد و یک متد منحصر به فرد به Car اضافه کن (مثلاً: play_music()).


۱۱.۱۳ | TIP: توابع در کلاس‌ها – self دقیقاً یعنی چه؟

self همیشه به “همین شی فعلی” اشاره داره، وقتی می‌نویسی self.name یعنی این مقدار متعلق به همین نمونه است.
مثلاً:

d1 = Dog("لوسی", 3)
d2 = Dog("هاپو", 2)
# هر دو شی ویژگی‌های خودشون رو دارن، با self بهشون دسترسی داریم.
محمد وب‌سایت

دیدگاهتان را بنویسید

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