الأساليب السحرية للحاويات
جزء من قسم Object Oriented Programming في رحلة Python على Coddy — الدرس 35 من 64.
تسمح الطرق السحرية للحاويات (Container magic methods) لفئاتك (classes) بالتصرف مثل الحاويات المدمجة (القوائم، القواميس، إلخ). فهي تُمكّن الفهرسة (indexing)، والتحقق من الطول (length checking)، والتكرار (iteration) على كائناتك المخصصة.
إليك مثال على فئة (class) تحتوي على دوال الحاوية السحرية (container magic methods):
class CustomList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __iter__(self):
return iter(self.items)
def __contains__(self, item):
return item in self.itemsتجعل الطريقة __len__ الدالة len() تعمل:
my_list = CustomList([1, 2, 3, 4])
print(len(my_list)) # 4تسمح الدالة __getitem__ باستخدام الفهرسة لاسترجاع العناصر:
print(my_list[2]) # 3
print(my_list[0]) # 1تسمح الطريقة __setitem__ باستخدام الفهرسة لعملية التعيين:
my_list[1] = 10
print(my_list[1]) # 10تجعل الطريقة __contains__ عامل التشغيل in يعمل:
print(3 in my_list) # True
print(100 in my_list) # Falseتُمكّن الطريقة __iter__ من إجراء التكرار:
for item in my_list:
print(item)المخرجات:
4
3
1
10
True
False
1
10
3
4نقطة رئيسية: تجعل الأساليب السحرية للحاويات (Container magic methods) مثل __len__، و __getitem__، و __setitem__، و __iter__، و __contains__ أصنافك المخصصة تتصرف مثل الحاويات المدمجة. يوفر هذا فهرسة، وتكراراً، واختبار عضوية بديهياً لكائناتك.
التحدي
متوسطفي هذا التحدي، ستقوم بتنفيذ فئة Deck تحاكي مجموعة أوراق اللعب بوظائف شاملة واتفاقيات Python الصحيحة.
تحتاج فقط إلى تعديل ملف deck.py. اتبع تعليقات TODO في الكود التي ترشدك خلال تنفيذ:
- تهيئة مجموعة أوراق لعب قياسية مكونة من 52 ورقة (باستخدام سلاسل نصية مثل "2H" و "KD" و "AS")
- دعم عمليات Python المدمجة:
- الفهرسة (
deck[0]) - التحقق من الطول (
len(deck)) - التكرار (
for card in deck) - اختبار العضوية (
"AS" in deck)
- الفهرسة (
- طريقة
shuffleلتبديل ترتيب الأوراق عشوائياً
ورقة مرجعية
تسمح الطرق السحرية للحاويات (Container magic methods) لفئاتك بالتصرف مثل الحاويات المدمجة (القوائم، القواميس، إلخ). فهي تُمكّن الفهرسة، والتحقق من الطول، والتكرار على كائناتك المخصصة.
الطرق السحرية الأساسية للحاويات:
__len__()- تُمكّن دالةlen()__getitem__()- تُمكّن الفهرسة للاسترجاع__setitem__()- تُمكّن الفهرسة للتعيين__iter__()- تُمكّن التكرار__contains__()- تُمكّن عامل التشغيلin
class CustomList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __iter__(self):
return iter(self.items)
def __contains__(self, item):
return item in self.itemsأمثلة على الاستخدام:
my_list = CustomList([1, 2, 3, 4])
# التحقق من الطول
print(len(my_list)) # 4
# الفهرسة
print(my_list[2]) # 3
my_list[1] = 10
# اختبار العضوية
print(3 in my_list) # True
# التكرار
for item in my_list:
print(item)جرّب بنفسك
from deck import Deck
# معالج حالات الاختبار الشامل
test_case = input()
def test_basic_functionality():
deck = Deck()
assert len(deck) == 52, f"Deck should have 52 cards, but has {len(deck)}"
first_card = deck[0]
assert isinstance(first_card, str), f"Card should be a string, but got {type(first_card)}"
assert "AS" in deck, "Ace of Spades should be in the deck"
assert "XY" not in deck, "XY is not a valid card and should not be in the deck"
cards = [card for card in deck]
assert len(cards) == 52, f"Iteration should yield 52 cards, but got {len(cards)}"
original_first_five = [deck[i] for i in range(5)]
deck.shuffle()
shuffled_first_five = [deck[i] for i in range(5)]
assert original_first_five != shuffled_first_five or len(deck) <= 5, "Shuffle should change card order"
print("Basic functionality tests passed!")
def test_edge_cases():
deck = Deck()
# اختبار الوصول إلى البطاقة الأولى والأخيرة
first_card = deck[0]
last_card = deck[51]
assert isinstance(first_card, str) and isinstance(last_card, str), "First and last cards should be strings"
# اختبار الفهرسة السالبة
assert deck[-1] == deck[51], "Negative indexing should work correctly"
# اختبار الوصول خارج الحدود
try:
invalid_card = deck[52]
print("Test failed: Should raise IndexError for out of bounds access")
except IndexError:
print("Edge case test passed: IndexError raised for out of bounds access")
print("Edge case tests passed!")
def test_card_uniqueness():
deck = Deck()
cards = [card for card in deck]
unique_cards = set(cards)
assert len(unique_cards) == 52, f"All cards should be unique, but found {len(unique_cards)} unique cards"
# التحقق من وجود بطاقات محددة
expected_cards = ["2H", "10S", "KD", "AC"]
for card in expected_cards:
assert card in deck, f"Expected card {card} not found in deck"
print("Card uniqueness tests passed!")
def test_shuffle_behavior():
deck = Deck()
original_order = [card for card in deck]
# التبديل الأول
deck.shuffle()
first_shuffle = [card for card in deck]
assert len(first_shuffle) == 52, "Shuffle should preserve all 52 cards"
assert set(first_shuffle) == set(original_order), "Shuffle should not add or remove cards"
# من المرجح جداً أن الترتيب قد تغير (على الرغم من وجود احتمال ضئيل جداً لعدم تغيره)
different_order = (original_order != first_shuffle)
# تبديل ثانٍ للتأكد تماماً
deck.shuffle()
second_shuffle = [card for card in deck]
different_order_2 = (first_shuffle != second_shuffle)
assert different_order or different_order_2, "Multiple shuffles should change the order"
print("Shuffle behavior tests passed!")
def test_contains_behavior():
deck = Deck()
# اختبار أن جميع البطاقات الصالحة موجودة في المجموعة
suits = ['H', 'D', 'C', 'S']
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
for suit in suits:
for rank in ranks:
card = rank + suit
assert card in deck, f"Valid card {card} should be in the deck"
# اختبار أن البطاقات غير الصالحة ليست في المجموعة
invalid_cards = ["1H", "11S", "XD", "AX", "JX", ""]
for card in invalid_cards:
assert card not in deck, f"Invalid card {card} should not be in the deck"
print("Contains behavior tests passed!")
def test_iteration_behavior():
deck = Deck()
# اختبار التكرار (Iteration)
card_count = 0
for card in deck:
card_count += 1
assert isinstance(card, str), f"Each card should be a string, but got {type(card)}"
assert card_count == 52, f"Iteration should yield 52 cards, but got {card_count}"
# اختبار التكرارات المتعددة
first_iteration = [card for card in deck]
second_iteration = [card for card in deck]
assert first_iteration == second_iteration, "Multiple iterations should yield the same order"
print("Iteration behavior tests passed!")
# تشغيل الاختبار المناسب بناءً على المدخلات
if test_case == "basic_functionality":
test_basic_functionality()
elif test_case == "edge_cases":
test_edge_cases()
elif test_case == "card_uniqueness":
test_card_uniqueness()
elif test_case == "shuffle_behavior":
test_shuffle_behavior()
elif test_case == "contains_behavior":
test_contains_behavior()
elif test_case == "iteration_behavior":
test_iteration_behavior()
else:
# الاختبار الافتراضي - تشغيل مجموعة الاختبارات الأصلية
def test_deck():
try:
# اختبار التهيئة والطول
deck = Deck()
assert len(deck) == 52, f"Deck should have 52 cards, but has {len(deck)}"
# اختبار getitem
first_card = deck[0]
assert isinstance(first_card, str), f"Card should be a string, but got {type(first_card)}"
# اختبار contains
assert "AS" in deck, "Ace of Spades should be in the deck"
assert "XY" not in deck, "XY is not a valid card and should not be in the deck"
# اختبار التكرار
cards = [card for card in deck]
assert len(cards) == 52, f"Iteration should yield 52 cards, but got {len(cards)}"
assert len(set(cards)) == 52, "All cards in the deck should be unique"
# اختبار التبديل (تحقق أساسي من تغير الترتيب)
original_first_five = [deck[i] for i in range(5)]
deck.shuffle()
shuffled_first_five = [deck[i] for i in range(5)]
assert original_first_five != shuffled_first_five or len(deck) <= 5, "Shuffle should change card order"
# التحقق من أن التبديل لا يفقد أي بطاقات
assert len(deck) == 52, f"Deck should still have 52 cards after shuffle, but has {len(deck)}"
print("All tests passed!")
except AssertionError as e:
print(f"Test failed: {e}")
test_deck()
print("Tests completed")يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsمعامل selfMethodsAttributesدالة البناء (__init__)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةدالة ()superإعادة تعريف الدوال (Method Overriding)الوراثة المتعددةترتيب استدعاء الدوال (Method Resolution Order)مراجعة - هيكلية الموظفين7الأساليب الخاصة
مقدمة في الأساليب السحريةتحميل المعاملات بشكل زائدالأساليب السحرية للحاوياتمراجعة - قائمة مخصصة5تعدد الأشكال
مراجعة إعادة تعريف الدوالمفهوم Duck Typingالأصناف والدوال المجردةتصميم الواجهاتملخص - حاسبة الأشكال