در بدنه یک کلاس چیزی که مینویسید یک مقدار است که همه نمونهها آن را میبینند. چیزی که داخل __init__ روی self میگذارید یک مقدار جدا برای هر نمونه است. این کل تفاوت است و همه رفتارهای بعدی از آن میآید.
class Peyk:shahr = "Karaj"یک مقدار، مشترک میان همه پیکهاdef __init__(self, kod): self.kod = kodیک مقدار بهازای هر پیک
با دو نمونه، Peyk.shahr = "Qazvin" هر دو را عوض میکند، چون هیچکدام نسخه خودشان را ندارند و هر دو همان یک مقدار را میخوانند. حالا a.shahr = "Hashtgerd" بنویسید: فقط همان یکی عوض میشود و Peyk.shahr دستنخورده میماند. آن انتساب کلاس را عوض نکرد، یک صفت نمونه ساخت، و میشود دیدش: 'shahr' in a.__dict__ جواب میدهد True و برای نمونه دیگر False.
و همینجاست که فهرست مشترک آدم را میگیرد
یک فهرست خالی در بدنه کلاس، مثل tahvil = []، همان قاعده را دارد و همان یک شی است برای همه. اما این بار انتسابی در کار نیست: a.tahvil.append("S-901") صفت تازهای نمیسازد، همان فهرست مشترک را عوض میکند. نتیجهاش این است که b.tahvil هم S-901 را دارد، برای پیکی که هیچوقت آن سفارش را نگرفت. تفاوت میان خواندن و انتساب اینجا کاملا معکوس نتیجه میدهد.
قاعدهای که این را جمع میکند: هر چیزی که میشود در جا عوضش کرد، فهرست و دیکشنری و مجموعه، باید داخل __init__ ساخته شود. بدنه کلاس فقط جای مقدارهای تغییرناپذیر است، یعنی عدد و رشته و چندتایی. همین تله در مقدار پیشفرض یک تابع هم هست و دلیلش یکی است: ورودی، خروجی، و جایی که دامنه نام تمام میشود.
self یک کلمه کلیدی نیست
پایتون نمونه را بهعنوان اولین آرگومان به متد پاس میدهد و نام آن آرگومان قرارداد است نه قانون. برای همین متدی که self نگیرد با پیامی درباره تعداد آرگومانها میشکند و نه با پیامی درباره کلاس، و برای همین Peyk.tahvil_bede(a) و a.tahvil_bede() دقیقا یک کار میکنند. فهمیدن این یک چیز، نصف سردرگمی درباره متدها را تمام میکند.
جایی که کار گیر میکند، کلاسی است که فقط جای متغیر است
در بیشتر کدهایی که در ایران بهعنوان اولین کار شیگرا نوشته میشود، کلاسها انباری از متغیرهایند و متدها فقط مقدار میگیرند و میگذارند. دلیلش این است که آموزشها با مثال ماشین و حیوان شروع میکنند و مثال هیچوقت به کاری نمیرسد. علامتش این است: اگر همه متدهای یک کلاس فقط خواندن و نوشتن صفتاند، آن کلاس یک دیکشنری است که گرانتر نوشته شده. چیزی که کلاس را توجیه میکند رفتار است، یعنی متدی که با داده خودش کاری میکند که بیرون از کلاس تکرار میشد. برای نگه داشتن صرف داده، dataclasses در کتابخانه استاندارد کوتاهتر و صریحتر است.
ابزار، و سالی که این حرف درست است
در سال ۲۰۲۶ dataclasses در کتابخانه استاندارد و رایگان است و جای نوشتن __init__ و __repr__ و مقایسه به دست را گرفته؛ نکتهای که مستقیما به این صفحه مربوط است این است که مقدار پیشفرض تغییرپذیر را رد میکند و بهجای یک باگ خاموش، همان لحظه خطا میدهد و field(default_factory=list) را میخواهد. برای دیدن اینکه یک صفت روی نمونه است یا روی کلاس، vars(a) در خود مفسر کافی است و فقط صفتهای نمونه را نشان میدهد.
پرسش بعدی این است که وقتی دو کلاس بیشتر رفتارشان یکی است، اشتراکشان کجا نوشته شود و کجا این کار تله میشود، که به اشتراک گذاشتن رفتار، و جایی که تله میشود است. و اگر فقط میخواهید بگویید چیزی چه کاری بلد است بیآنکه بگویید چطور، نام بردن یک توانایی، بدون نام بردن پیادهسازی جواب دیگری است.