Phương thức ma thuật của vùng chứa
Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 35 trên 64.
Các phương thức ma thuật của vùng chứa giúp lớp của bạn hoạt động như các vùng chứa có sẵn (danh sách, từ điển, v.v.). Chúng cho phép lập chỉ mục, kiểm tra độ dài và lặp qua các đối tượng tùy chỉnh của bạn.
Đây là ví dụ về một lớp có các phương thức ma thuật của vùng chứa:
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.itemsPhương thức __len__ giúp len() hoạt động:
my_list = CustomList([1, 2, 3, 4])
print(len(my_list)) # 4Phương thức __getitem__ cho phép truy xuất bằng chỉ số:
print(my_list[2]) # 3
print(my_list[0]) # 1Phương thức __setitem__ cho phép gán bằng chỉ số:
my_list[1] = 10
print(my_list[1]) # 10Phương thức __contains__ giúp toán tử in hoạt động:
print(3 in my_list) # True
print(100 in my_list) # FalsePhương thức __iter__ cho phép thực hiện lần lặp:
for item in my_list:
print(item)Đầu ra:
4
3
1
10
True
False
1
10
3
4Điểm chính: Các phương thức ma thuật của vùng chứa như __len__, __getitem__, __setitem__, __iter__ và __contains__ giúp lớp tùy chỉnh hoạt động như các vùng chứa dựng sẵn. Nhờ đó, bạn có thể lấy phần tử theo chỉ số, lặp qua các đối tượng và kiểm tra phần tử có thuộc đối tượng hay không một cách trực quan.
Thử thách
Trung bìnhTrong thử thách này, bạn sẽ triển khai lớp Deck mô phỏng một bộ bài tây, với đầy đủ chức năng và tuân theo các quy ước của Python.
Bạn chỉ cần chỉnh sửa tệp deck.py. Hãy làm theo các chú thích TODO trong code, hướng dẫn bạn triển khai:
- Khởi tạo bộ bài tiêu chuẩn gồm 52 lá (sử dụng các chuỗi như "2H", "KD", "AS")
- Hỗ trợ các thao tác tích hợp sẵn của Python:
- Truy cập bằng chỉ số (
deck[0]) - Kiểm tra độ dài (
len(deck)) - Lặp qua các phần tử (
for card in deck) - Kiểm tra phần tử có thuộc bộ bài hay không (
"AS" in deck)
- Truy cập bằng chỉ số (
- Một phương thức
shuffleđể xáo trộn thứ tự các lá bài
Tự làm thử
from deck import Deck
# Xử lý toàn diện các test case
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()
# Kiểm tra cách truy cập lá bài đầu tiên và cuối cùng
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"
# Kiểm tra cách truy cập bằng chỉ số âm
assert deck[-1] == deck[51], "Negative indexing should work correctly"
# Kiểm tra cách truy cập ngoài phạm vi chỉ số
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"
# Xác nhận sự tồn tại của các lá bài cụ thể
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]
# Xáo bài lần đầu
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"
# Thứ tự rất có thể đã thay đổi (dù vẫn có xác suất rất nhỏ là không)
different_order = (original_order != first_shuffle)
# Xáo bài lần thứ hai để chắc chắn hơn
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()
# Kiểm tra tất cả lá bài hợp lệ đều có trong bộ bài
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"
# Kiểm tra các lá bài không hợp lệ đều không có trong bộ bài
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()
# Kiểm tra lần lặp (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}"
# Kiểm tra nhiều lần lặp
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!")
# Chạy bài kiểm tra phù hợp dựa trên đầu vào
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:
# Bài kiểm tra mặc định: chạy bộ kiểm tra ban đầu
def test_deck():
try:
# Kiểm tra việc khởi tạo và độ dài
deck = Deck()
assert len(deck) == 52, f"Deck should have 52 cards, but has {len(deck)}"
# Kiểm tra getitem
first_card = deck[0]
assert isinstance(first_card, str), f"Card should be a string, but got {type(first_card)}"
# Kiểm tra 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"
# Kiểm tra lần lặp (iteration)
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"
# Kiểm tra shuffle (kiểm tra cơ bản xem thứ tự có thay đổi không)
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"
# Kiểm tra xem shuffle có làm mất lá bài nào không
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")Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên7Phương thức đặc biệt
Giới thiệu về phương thức ma thuậtNạp chồng toán tửPhương thức ma thuật của vùng chứaÔn tập: danh sách tùy chỉnh2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnhTự luyện tập: Trình biên dịch Python online