Table of Contents
نقش متد `__init__` در کلاسها
در فصل والد، با مفهوم «کلاس» و «شیء» آشنا شدهاید. اینجا تمرکز ما فقط روی یک متد خاص در کلاسهاست: متد سازنده یا همان __init__.
متد سازنده (Constructor) چیست؟
وقتی از روی یک کلاس، شیء جدید میسازید (مثلاً User() یا Car())، پایتون میتواند بهطور خودکار کدی را اجرا کند تا آن شیء را «آمادهٔ استفاده» کند.
این کار با متدی به نام __init__ انجام میشود.
بهصورت ساده:
__init__متدی است که هنگام ساختن یک شیء جدید از کلاس، بهطور خودکار صدا زده میشود.- معمولاً برای شروع مقداردهی ویژگیها (attributes) از آن استفاده میکنیم.
ساختار کلی:
class ClassName:
def __init__(self, پارامترها):
# کد مقداردهی اولیه
...شکل کلی `__init__` و نقش `self`
رایجترین امضا (signature) برای __init__ به این شکل است:
class Person:
def __init__(self, name, age):
self.name = name
self.age = ageنکتهها:
- اولین پارامتر همیشه
selfاست (قرارداد نامگذاری).
selfبه همان شیء در حال ساختهشدن اشاره میکند. - بقیهٔ پارامترها (
name,age) مقادیری هستند که هنگام ساخت شیء میدهید. - درون
__init__، با استفاده ازself.ویژگی، دادهها را روی شیء ذخیره میکنید.
مثال استفاده:
p1 = Person("Ali", 20)
print(p1.name) # خروجی: Ali
print(p1.age) # خروجی: 20
هنگام اجرای Person("Ali", 20) در پشت صحنه این اتفاق میافتد:
۱. پایتون یک شیء خالی از کلاس Person میسازد.
۲. سپس بهطور خودکار صدا میزند:
Person.__init__(p1, "Ali", 20)
(که در کد ما به صورت def __init__(self, name, age): تعریف شده است.)
مقداردهی ویژگیها با `__init__`
مهمترین کاربرد __init__، مقداردهی ویژگیهای شیء است:
class Book:
def __init__(self, title, pages, price):
self.title = title
self.pages = pages
self.price = price
b = Book("Python for Beginners", 250, 150000)
print(b.title) # Python for Beginnersالگوی ذهنی خوب:
- پارامترهای
__init__ورودی هستند. - ویژگیهای
self، دادههای ذخیرهشده روی شیء هستند.
$$
\text{پارامتر تابع} \longrightarrow \text{self.ویژگی}
$$
`__init__` بدون پارامتر (بهجز `self`)
لازم نیست همیشه __init__ پارامترهای اضافی داشته باشد.
گاهی فقط میخواهیم مقادیر پیشفرض بگذاریم:
class Counter:
def __init__(self):
self.value = 0
c = Counter()
print(c.value) # 0اینجا سازنده هیچ ورودی از بیرون نمیگیرد، اما درون خودش مقداردهی اولیه انجام میدهد.
مقادیر پیشفرض پارامترها در `__init__`
مثل توابع عادی، در __init__ هم میتوانید پارامترهای اختیاری با مقدار پیشفرض داشته باشید:
class User:
def __init__(self, username, is_admin=False):
self.username = username
self.is_admin = is_admin
u1 = User("ali") # is_admin = False
u2 = User("admin_user", True) # is_admin = Trueاینجا:
- اگر مقدار
is_adminرا ندهید، بهطور پیشفرضFalseخواهد بود. - اگر بدهید، همان مقدار استفاده میشود.
این کار ساخت اشیاء را انعطافپذیرتر میکند.
تفاوت `__init__` با متدهای عادی
همهٔ متدهای کلاس از نظر شکل کلی شبیهاند، اما __init__ چند تفاوت مهم دارد:
- نامش دقیقاً باید
__init__باشد (با دو خط زیر در ابتدا و انتها). - هنگام ساخت شیء، خودکار اجرا میشود؛ نیازی نیست دستی صدا بزنید.
- معمولاً برای مقداردهی اولیهٔ ویژگیها استفاده میشود؛ متدهای دیگر برای «عمل» روی آن دادهها هستند.
مثال مقایسه:
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance # مقدار اولیه
def deposit(self, amount):
self.balance += amount # عمل روی دادههای موجود
acc = BankAccount("Sara", 1000) # __init__ خودکار اجرا میشود
acc.deposit(500) # متد عادی، دستی فراخوانی میشود
print(acc.balance) # 1500اعتبارسنجی ورودیها در `__init__`
میتوانید در __init__ ورودیها را بررسی کنید و در صورت نامعتبر بودن، خطا بدهید یا اصلاح کنید:
class Product:
def __init__(self, name, price):
self.name = name
if price < 0:
raise ValueError("قیمت نمیتواند منفی باشد")
self.price = price
# p = Product("Phone", -100) # این خط خطا ایجاد میکنداین کار کمک میکند هر شیء ساختهشده، حالت معتبری داشته باشد.
استفاده از `__init__` برای محاسبات اولیه
گاهی لازم است قبل از استفاده از شیء، یکسری محاسبات اولیه انجام شود.
این کار نیز جای خوبی در __init__ دارد:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
self.area = width * height # محاسبه و ذخیرهٔ مساحت
r = Rectangle(3, 4)
print(r.area) # 12پارامترهای زیاد در `__init__` (و توصیهٔ عملی)
مثلاً:
class Student:
def __init__(self, first_name, last_name, age, student_id, major, gpa):
self.first_name = first_name
self.last_name = last_name
self.age = age
self.student_id = student_id
self.major = major
self.gpa = gpaنکتهٔ عملی:
- از نظر فنی مشکلی نیست، اما اگر پارامترها خیلی زیاد شوند،
خوانایی کد کم میشود و احتمال اشتباه در ترتیب آرگومانها بالا میرود. - برای شروع، فقط این را بدانید که میتوانید پارامترها را نامگذاریشده ارسال کنید تا ترتیب مهم نباشد:
s = Student(first_name="Ali", last_name="Ahmadi",
age=21, student_id="401234",
major="CS", gpa=18.5)چند نمونهٔ ساده از کلاسها با `__init__`
مثال: کلاس کاربر ساده
class SimpleUser:
def __init__(self, username, email):
self.username = username
self.email = email
def info(self):
return f"{self.username} - {self.email}"
u = SimpleUser("ali", "ali@example.com")
print(u.info()) # ali - ali@example.com
اینجا __init__ فقط اطلاعات اولیه را ذخیره میکند، متد info از آنها استفاده میکند.
مثال: شمارنده با مقدار شروع دلخواه
class Counter:
def __init__(self, start=0):
self.value = start
def increment(self):
self.value += 1
c1 = Counter() # شروع از 0
c2 = Counter(10) # شروع از 10
c1.increment()
c2.increment()
print(c1.value) # 1
print(c2.value) # 11آیا میتوان کلاس بدون `__init__` داشت؟
بله. اگر __init__ تعریف نکنید، پایتون خودش یک سازندهٔ پیشفرض در نظر میگیرد که هیچ کار خاصی انجام نمیدهد:
class Empty:
pass
e = Empty() # بدون __init__ هم کار میکنداما:
- در عمل، در اکثر کلاسهای واقعی، برای مقداردهی اولیه از
__init__استفاده میشود. - وقتی میخواهید شیء شما حالت اولیهٔ مشخصی داشته باشد، تقریباً همیشه باید
__init__بنویسید.
نکات رایج و اشتباهات معمول با `__init__`
۱. فراموش کردن self:
class Person:
def __init__(name, age): # اشتباه: self باید اولین پارامتر باشد
name = name
age = ageدرست:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
۲. استفاده نکردن از self.:
class Person:
def __init__(self, name):
name = name # این فقط یک متغیر محلی است، روی شیء ذخیره نمیشوددرست:
class Person:
def __init__(self, name):
self.name = name # حالا روی شیء ذخیره میشود۳. ندادن آرگومان کافی هنگام ساخت شیء:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("Ali") # TypeError: آرگومان age داده نشدهباید:
p = Person("Ali", 20)یا سن را پیشفرض کنید:
class Person:
def __init__(self, name, age=18):
self.name = name
self.age = ageتمرینهای پیشنهادی
برای تمرین، این ایدهها را پیادهسازی کنید:
- کلاسی به نام
Dogتعریف کنید که در__init__نام و نژاد سگ را بگیرد و یک متدbarkداشته باشد که پیامی شامل نام سگ چاپ کند. - کلاسی به نام
Pointبسازید که مختصات $x$ و $y$ را در__init__بگیرد و در همانجا فاصله از مبدأ را در ویژگیای به نامdistance_from_originحساب و ذخیره کند. - کلاسی به نام
Movieتعریف کنید که عنوان، سال تولید و امتیاز را در__init__بگیرد و اگر امتیاز کمتر از ۰ یا بیشتر از ۱۰ بود، آن را به نزدیکترین مقدار معتبر (۰ یا ۱۰) محدود کند.
در این تمرینها فقط روی استفاده از __init__ برای مقداردهی اولیه، اعتبارسنجی و محاسبهٔ اولیه تمرکز کنید.