Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

تحميل المعاملات بشكل زائد

جزء من قسم Object Oriented Programming في رحلة Python على Coddy — الدرس 34 من 64.

يسمح تحميل المعاملات الزائد (Operator overloading) لفئاتك (classes) بالعمل مع معاملات بايثون المدمجة (+، -، *، إلخ) من خلال تنفيذ دوال سحرية (magic methods) خاصة.

إليك مثال على فئة (class) مع تحميل زائد للمعاملات (operator overloading):

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

تحدد الطريقة __add__ ما يحدث عند استخدام العامل +:

v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2  # تستدعي v1.__add__(v2)
print(result)

تحدد الطريقة __mul__ ما يحدث عند استخدام المعامل *:

v1 = Vector(2, 3)
scaled = v1 * 3   # يستدعي v1.__mul__(3)
print(scaled)

المخرجات:

Vector(7, 10)
Vector(6, 9)

أضف معاملات المقارنة:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(1, 1)

print(v1 == v2)  # True - يستدعي v1.__eq__(v2)
print(v1 == v3)  # False

نقطة رئيسية: يستخدم تحميل المعاملات بشكل زائد (Operator overloading) الأساليب السحرية (magic methods) مثل __add__ (+)، و __sub__ (-)، و __mul__ (*)، و __eq__ (==) لتحديد كيفية عمل المعاملات مع كائناتك. وهذا يجعل فئاتك (classes) تتصرف بشكل طبيعي مع معاملات بايثون المدمجة.

challenge icon

التحدي

متوسط

في هذا التحدي، ستقوم بتنفيذ فئة Money التي تمثل مبالغ نقدية مع تحميل زائد قوي للعوامل (operator overloading). سيتم اختبار تنفيذك بدقة مقابل مجموعة اختبار شاملة.

  • money.py - هذا هو الملف الوحيد الذي تحتاج إلى تعديله. يحتوي على تعريف الفئة مع تعليقات TODO لإرشادك في التنفيذ.
  • driver.py - يحتوي على سيناريوهات اختبار واسعة تتحقق من صحة تنفيذك (لا تقم بتعديله).

قم بتنفيذ فئة Money مع الميزات التالية:

  1. منشئ (Constructor) يأخذ amount (float) و currency (string)
  2. الجمع (+) لكائنات Money التي لها نفس العملة
  3. الضرب (*) في رقم لتغيير حجم المبلغ
  4. مقارنة المساواة (==) بين كائنات Money
  5. تمثيل نصي بتنسيق "X.XX CUR"

ورقة مرجعية

يسمح تحميل المعاملات الزائد (Operator overloading) للأصناف (classes) بالعمل مع معاملات بايثون المدمجة من خلال تنفيذ طرق سحرية (magic methods) خاصة:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

الطرق السحرية الشائعة لتحميل المعاملات الزائد:

  • __add__ للمعامل +
  • __sub__ للمعامل -
  • __mul__ للمعامل *
  • __eq__ للمعامل ==
  • __str__ لتمثيل السلسلة النصية

مثال على الاستخدام:

v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2  # يستدعي v1.__add__(v2)
scaled = v1 * 3   # يستدعي v1.__mul__(3)
print(v1 == v2)   # يستدعي v1.__eq__(v2)

جرّب بنفسك

from money import Money

# معالج حالات الاختبار
test_case = input()

def test_basic_functionality():
    # اختبار التهيئة والتمثيل النصي
    m1 = Money(10.0, "USD")
    assert str(m1) == "10.00 USD", f"__str__ method failed, got {str(m1)}"
    
    # اختبار الجمع
    m2 = Money(20.0, "USD")
    m3 = m1 + m2
    assert str(m3) == "30.00 USD", f"Addition failed, got {str(m3)}"
    
    # اختبار جمع عملات مختلفة
    m4 = Money(20.0, "EUR")
    try:
        m5 = m1 + m4
        assert False, "Adding different currencies should raise an error"
    except ValueError as e:
        assert str(e) == "Cannot add different currencies", f"Wrong error message: {str(e)}"
    
    # اختبار الضرب
    m6 = m1 * 3
    assert str(m6) == "30.00 USD", f"Multiplication failed, got {str(m6)}"
    
    # اختبار التساوي
    assert m1 == Money(10.0, "USD"), "Equality test failed"
    assert m1 != m2, "Inequality test failed"
    
    print("All basic functionality tests passed!")

def test_zero_values():
    # اختبار بقيمة صفرية
    m1 = Money(0.0, "USD")
    assert str(m1) == "0.00 USD", f"Zero amount string representation failed, got {str(m1)}"
    
    # اختبار الجمع مع الصفر
    m2 = Money(10.0, "USD")
    m3 = m1 + m2
    assert str(m3) == "10.00 USD", f"Addition with zero failed, got {str(m3)}"
    
    # اختبار الضرب في صفر
    m4 = m2 * 0
    assert str(m4) == "0.00 USD", f"Multiplication by zero failed, got {str(m4)}"
    
    # اختبار التساوي مع قيمة صفرية
    assert m1 == Money(0.0, "USD"), "Equality with zero amount failed"
    assert m1 != m2, "Inequality with zero amount failed"
    
    print("All zero value tests passed!")

def test_negative_values():
    # اختبار بقيمة سالبة
    m1 = Money(-10.0, "USD")
    assert str(m1) == "-10.00 USD", f"Negative amount string representation failed, got {str(m1)}"
    
    # اختبار الجمع مع قيم سالبة
    m2 = Money(20.0, "USD")
    m3 = m1 + m2
    assert str(m3) == "10.00 USD", f"Addition with negative amount failed, got {str(m3)}"
    
    m4 = Money(-5.0, "USD")
    m5 = m1 + m4
    assert str(m5) == "-15.00 USD", f"Addition of two negative amounts failed, got {str(m5)}"
    
    # اختبار الضرب في عدد قياسي سالب
    m6 = m2 * -2
    assert str(m6) == "-40.00 USD", f"Multiplication by negative scalar failed, got {str(m6)}"
    
    # اختبار التساوي مع قيم سالبة
    assert m1 == Money(-10.0, "USD"), "Equality with negative amount failed"
    assert m1 != m2, "Inequality with negative amount failed"
    
    print("All negative value tests passed!")

def test_large_values():
    # اختبار بقيم كبيرة جداً
    m1 = Money(1000000.0, "USD")
    assert str(m1) == "1000000.00 USD", f"Large amount string representation failed, got {str(m1)}"
    
    # اختبار الجمع مع قيم كبيرة
    m2 = Money(2000000.0, "USD")
    m3 = m1 + m2
    assert str(m3) == "3000000.00 USD", f"Addition with large amounts failed, got {str(m3)}"
    
    # اختبار الضرب في عدد قياسي كبير
    m4 = m1 * 1000
    assert str(m4) == "1000000000.00 USD", f"Multiplication with large scalar failed, got {str(m4)}"
    
    print("All large value tests passed!")

def test_precision():
    # اختبار مع مبالغ كسرية
    m1 = Money(10.25, "USD")
    assert str(m1) == "10.25 USD", f"Fractional amount string representation failed, got {str(m1)}"
    
    m2 = Money(10.2, "USD")
    assert str(m2) == "10.20 USD", f"Two decimal place formatting failed, got {str(m2)}"
    
    # اختبار الجمع مع مبالغ كسرية
    m3 = Money(0.75, "USD")
    m4 = m1 + m3
    assert str(m4) == "11.00 USD", f"Addition with fractional amounts failed, got {str(m4)}"
    
    # اختبار الضرب في عدد قياسي كسري
    m5 = m1 * 0.5
    assert str(m5) == "5.13 USD", f"Multiplication with fractional scalar failed, got {str(m5)}"
    
    print("All precision tests passed!")

def test_type_validation():
    try:
        # يجب أن تعمل هذه العمليات بدون أخطاء
        m1 = Money(10.0, "USD")
        m2 = m1 * 2
        m3 = m1 * 2.5
        
        # اختبار التساوي مع أنواع مختلفة
        assert (m1 == "10.00 USD") == False, "Equality with string should return False"
        assert (m1 == 10.0) == False, "Equality with number should return False"
        
        print("All type validation tests passed!")
    except Exception as e:
        print(f"Type validation test failed: {e}")

def test_currency_case_sensitivity():
    # اختبار حساسية حالة الأحرف للعملة
    m1 = Money(10.0, "USD")
    m2 = Money(10.0, "usd")
    
    # يجب أن تكون العملات حساسة لحالة الأحرف
    assert m1 != m2, "Currency comparison should be case-sensitive"
    
    # يجب أن يفشل الجمع بين حالات أحرف مختلفة
    try:
        m3 = m1 + m2
        assert False, "Adding different currency cases should raise an error"
    except ValueError as e:
        assert str(e) == "Cannot add different currencies", f"Wrong error message: {str(e)}"
    
    print("All currency case sensitivity tests passed!")

def test_performance():
    # إنشاء العديد من كائنات Money وإجراء العمليات
    base = Money(1.0, "USD")
    result = base
    
    # إجراء 1000 عملية جمع
    for i in range(1000):
        result = result + Money(1.0, "USD")
    
    assert str(result) == "1001.00 USD", f"Performance test addition failed, got {str(result)}"
    
    # إجراء 10 عمليات ضرب
    result = base
    for i in range(10):
        result = result * 2
    
    assert str(result) == "1024.00 USD", f"Performance test multiplication failed, got {str(result)}"
    
    print("All performance tests passed!")

# تشغيل الاختبار المناسب بناءً على المدخلات
if test_case == "basic_test":
    test_basic_functionality()
elif test_case == "zero_values":
    test_zero_values()
elif test_case == "negative_values":
    test_negative_values()
elif test_case == "large_values":
    test_large_values()
elif test_case == "precision":
    test_precision()
elif test_case == "type_validation":
    test_type_validation()
elif test_case == "currency_case":
    test_currency_case_sensitivity()
elif test_case == "performance":
    test_performance()
else:
    print(f"Unknown test case: {test_case}")
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming