الفئات والكائنات
في الدروس القليلة الماضية، نظّمنا الكود باستخدام الدوال — نهج "إجرائي" يركز على "ماذا تفعل." البرمجة كائنية التوجه (OOP) تركز على "من يفعل" — تضمين البيانات والطرق التي تعمل على تلك البيانات في كائن. كل شيء في بايثون هو كائن؛ فهم OOP هو خطوة رئيسية للأمام.
1. ما هي الفئات والكائنات
الفئة هي مخطط؛ الكائن هو نسخة ملموسة تم إنشاؤها من ذلك المخطط.
# عرّف فئة "كلب" — المخطط
class Dog:
pass
# أنشئ كائنات "كلب" محددة من المخطط
my_dog = Dog()
print(type(my_dog)) # <class '__main__.Dog'>
print(my_dog) # <__main__.Dog object at 0x...>
مثل "الكلب" كسلالة هو مفهوم (فئة)، الكلب المحدد المسمى Wangcai الذي تملكه هو نسخة (كائن). فئة واحدة يمكنها إنشاء عدد لا يحصى من الكائنات.
2. __init__: طريقة المُنشئ
عند إنشاء كائن، يتم استدعاء طريقة __init__ تلقائياً لتهيئة سمات الكائن:
class Dog:
"""فئة الكلب"""
def __init__(self, name, age):
self.name = name # سمة المثال
self.age = age
# مرر المعاملات عند إنشاء الكائنات
dog1 = Dog("Wangcai", 3)
dog2 = Dog("Xiaobai", 1)
print(dog1.name) # Wangcai
print(dog2.name) # Xiaobai
print(dog1.age) # 3
ملاحظة:
__init__ليس المُنشئ — الكائن يُنشأ قبل استدعائه. المُنشئ الفعلي هو__new__، لكنك لا تحتاج أبداً للمساس به تقريباً. المعامل الأول لـ__init__هو دائماًself، الذي يمثل نسخة الكائن الحالية.
مثال: تعريف فئة طالب (الصعوبة ⭐)
class Student:
"""فئة الطالب"""
def __init__(self, name, student_id, score):
self.name = name
self.student_id = student_id
self.score = score
def introduce(self):
"""تقديم الذات"""
return f"My name is {self.name}, ID: {self.student_id}, score: {self.score}."
def is_pass(self):
"""تحقق من النجاح"""
return self.score >= 60
# أنشئ كائنات الطلاب
s1 = Student("Zhang San", "2024001", 85)
s2 = Student("Li Si", "2024002", 45)
print(s1.introduce()) # My name is Zhang San, ID: 2024001, score: 85.
print(s2.introduce()) # My name is Li Si, ID: 2024002, score: 45.
print(f"Is Zhang San passing? {s1.is_pass()}") # True
print(f"Is Li Si passing? {s2.is_pass()}") # False
3. الطرق: سلوكيات الكائن
الدوال المُعرّفة داخل الفئة تُسمى طرقاً. معاملها الأول هو دائماً self — الذي يمثل الكائن نفسه الذي يستدعي الطريقة.
class Calculator:
"""آلة حاسبة بسيطة"""
def __init__(self):
self.result = 0
def add(self, value):
self.result += value
return self
def subtract(self, value):
self.result -= value
return self
def show(self):
return self.result
calc = Calculator()
calc.add(10)
calc.subtract(3)
print(calc.show()) # 7
# تسلسل الطرق — كل طريقة تُرجع self
result = Calculator().add(10).subtract(3).add(5).show()
print(result) # 12
self يمكن تسلسلها. العديد من مكتبات بايثون (مثل pandas) تستخدم هذا النمط بشكل مكثف.
4. سمات المثال مقابل سمات الفئة
يمكن تعريف السمات على المثال (فريدة لكل كائن) أو على الفئة (مشتركة بين جميع الكائنات):
class Student:
# سمة الفئة — مشتركة بين جميع الطلاب
school = "First High School"
total_count = 0
def __init__(self, name):
# سمة المثال — فريدة لكل طالب
self.name = name
Student.total_count += 1
s1 = Student("Zhang San")
s2 = Student("Li Si")
# سمات الفئة تُتاح عبر اسم الفئة
print(Student.school) # First High School
print(Student.total_count) # 2
# يمكن الوصول إليها أيضاً عبر المثيلات (إذا لم توجد سمة مثال بنفس الاسم)
print(s1.school) # First High School
print(s2.school) # First High School
# تعديل سمة الفئة يؤثر على جميع المثيلات
Student.school = "Second High School"
print(s1.school) # Second High School
مثال: حساب بنكي (الصعوبة ⭐⭐)
class BankAccount:
"""حساب بنكي"""
bank_name = "Python Bank" # سمة فئة
interest_rate = 0.003 # معدل فائدة سنوي 0.3%
def __init__(self, owner, balance=0):
self.owner = owner # سمة مثال
self.balance = balance # سمة مثال
def deposit(self, amount):
self.balance += amount
return f"Deposited {amount}, balance: {self.balance}"
def withdraw(self, amount):
if amount > self.balance:
return "Insufficient balance!"
self.balance -= amount
return f"Withdrew {amount}, balance: {self.balance}"
def yearly_interest(self):
"""احسب الفائدة السنوية"""
interest = self.balance * BankAccount.interest_rate
return f"Yearly interest: {interest:.2f}"
acc1 = BankAccount("Zhang San", 10000)
acc2 = BankAccount("Li Si", 5000)
print(acc1.deposit(5000)) # Deposited 5000, balance: 15000
print(acc2.withdraw(2000)) # Withdrew 2000, balance: 3000
print(acc1.yearly_interest()) # Yearly interest: 4.50
# جميع الحسابات تشترك في نفس معدل الفائدة
print(acc1.interest_rate) # 0.003
print(acc2.interest_rate) # 0.003
حالات الاستخدام الشائعة
- نمذجة البيانات: طبّق كيانات العالم الحقيقي إلى كود — المستخدمون والطلبات والمنتجات كلها ممثلة بفئات.
- إدارة الحالة: الكائنات تحتفظ بحالة (سمات)، والطرق تعالج تلك الحالة — مثل شخصيات اللعبة، عربات التسوق.
- تنظيم الكود: البيانات والوظائف ذات الصلة مُجمّعة معاً، أنظف من الدوال المتناثرة.
- تمديد الأطراف: نماذج Django، تطبيق Flask، مكونات واجهة المستخدم الرسومية كلها مُنفّذة عبر الفئات.
❓ أسئلة شائعة
self كأول معامل. الدوال يمكن أن توجد بشكل مستقل؛ الطرق يجب أن تُستدعَى عبر كائن أو فئة. أساساً، الطرق هي دوال حيث تمرر بايثون المتصل تلقائياً كأول وسيطة.
س:هل يمكن إعادة تسمية self إلى شيء آخر؟ ج:تقنياً نعم، لكن لا تغيره أبداً. self هي قاعدة صارمة في مجتمع بايثون. تغيير الاسم سيعمل، لكن أي شخص يقرأ كودك (بما فيهم أنت في المستقبل) سيجده غريباً. استخدم دائماً self.
س:متى يجب استخدام فئة مقابل دالة؟ ج:إذا كنت بحاجة للحفاظ على حالة (بيانات)، استخدم فئة — مثل حساب بنكي يتتبع الرصيد. إذا كنت تقوم بحساب لمرة واحدة (إدخال ← معالجة ← إخراج)، استخدم دالة — مثل تحويل درجة الحرارة. قاعدة بسيطة: إذا كنت تحتاج فقط 1-2 دالة، الدوال كافية؛ إذا كانت دوال متعددة ذات صلة تشارك نفس البيانات، استخدم فئة.📖 ملخص
- الفئة هي مخطط؛ الكائن هو نسخة ملموسة تم إنشاؤها منه
__init__هي طريقة التهيئة، تُستدعى تلقائياً عند إنشاء كائن- المعامل الأول للطرق هو
self، الذي يمثل الكائن الحالي - سمات المثال فريدة لكل كائن؛ سمات الفئة مشتركة بين جميع الكائنات
- الفئات تضم البيانات والطرق التي تعمل على تلك البيانات معاً
📝 تمارين
-
مبتدئ (الصعوبة ⭐): عرّف فئة
Carبسماتbrandوcolorوspeed. تضمين طريقةaccelerate(value)لزيادة السرعة وطريقةshow_speed()لعرض السرعة الحالية. -
متوسط (الصعوبة ⭐⭐): عرّف فئة
Student. استخدم سمة فئة لتتبع العدد الإجمالي للطلاب، وسمات مثال لتسجيل اسم ودرجة كل طالب. نفّذ طريقةget_grade()تُرجع تقديراً حرفياً (A, B, C, D). -
متقدم (الصعوبة ⭐⭐⭐): عرّف فئة
LibraryوفئةBook.Bookلها عنوان ومؤلف وحالة استعارة.Libraryلها أربع طرق:add_book(book)،borrow(title)،return_book(title)، وshow_books().



