نظِّم كودك بأصناف مصمَّمة جيدًا: التهيئة، وسمات المثيل أو سمات الصنف، والوراثة ومقايضاتها.
افتح هذا الدرس في Kodokonأنت تتعامل مع كائنات Python طوال الوقت: السلاسل النصية، والقوائم، والملفات. وكتابة أصنافك الخاصة تعني تجميع الحالة (السمات) والسلوك (التوابع) خلف واجهة متماسكة. نقطة مصطلحية كثيرًا ما يُساء فهمها: __init__ ليست بانيًا للكائن. فالكائن موجود سلفًا (أنشأه __new__) عندما تتلقّى __init__ المعامل self؛ ومهمتها هي تهيئة المثيل. أما self فلا شيء سحري فيه: إنه المعامل الأول لكل تابع مثيل، وتمرّره Python تلقائيًا عند الاستدعاء.
class Account:
def __init__(self, owner, balance=0.0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("amount must be > 0")
self.balance += amount
return self.balance
def __repr__(self):
return f"Account({self.owner!r}, {self.balance})"
account = Account("Ada")
account.deposit(120.0)
print(account)تمييز حاسم في الواقع العملي: سمات الصنف يُصرَّح بها في جسم الصنف وتتشاركها كل المثيلات؛ أما سمات المثيل فتُنشأ على self، عادةً داخل __init__. وعند القراءة، تبحث Python أولًا في المثيل، ثم ترجع إلى الصنف، ثم إلى الأصناف الأب. والإسناد self.x = ... ينشئ دائمًا سمة مثيل، تحجب سمة الصنف التي تحمل الاسم نفسه. أما المزلق الكلاسيكي في الواقع العملي فهو سمة صنف قابلة للتغيير.
class Basket:
items = []
def add(self, item):
self.items.append(item)
a = Basket()
b = Basket()
a.add("apple")
print(b.items) # ['apple']: shared list!تعبّر الوراثة عن علاقة "هو نوع من": فالصنف Car هو نوع من Vehicle. يرث الصنف الفرعي التوابع، ويمكنه إعادة تعريفها، وتتيح له super() استدعاء نسخة الأب - وهي لا غنى عنها داخل __init__ حتى لا تتخطى تهيئة الأب. وتحلّ Python الاستدعاءات باتّباع MRO (ترتيب تحليل التوابع). لا تلجأ إلى الوراثة بشكل منهجي: فلإعادة استخدام الكود دون علاقة "هو نوع من"، فضِّل التركيب (كائن يملك كائنًا آخر). والتسلسلات الهرمية العميقة هشّة: إذ يصبح كل صنف أب واجهة برمجية ضمنية لجميع أبنائه.
class Vehicle:
def __init__(self, brand):
self.brand = brand
def describe(self):
return self.brand
class Car(Vehicle):
def __init__(self, brand, doors):
super().__init__(brand)
self.doors = doors
def describe(self):
base = super().describe()
return f"{base}, {self.doors} doors"
print(Car("Aster", 5).describe())