Giới thiệu
Một hạn chế cơ bản của giải nén (unpacking) trong Python là bạn phải biết trước độ dài của chuỗi (sequence) cần giải nén.
Cách thực hiện
Ví dụ: Tìm số lớn nhất và lớn thứ hai
random_numbers = [0, 1, 5, 9, 17, 12, 7, 10, 3, 2]
random_numbers_descending = sorted(random_numbers, reverse=True)
print(f"Output \n*** {random_numbers_descending}")
# Kết quả: [17, 12, 10, 9, 7, 5, 3, 2, 1, 0]
Nếu thử giải nén vào 2 biến:
largest, second_largest = random_numbers_descending
# ValueError: too many values to unpack (expected 2)
Cách truyền thống: Indexing và Slicing
largest = random_numbers_descending[0]
second_largest = random_numbers_descending[1]
rest_of_numbers = random_numbers_descending[2:]
Cách này hoạt động nhưng code rối, dễ sai khi chia chuỗi thành nhiều tập con.
Cách tốt hơn: Starred Expression (Biểu thức dấu sao)
Python hỗ trợ giải nén "bắt tất cả" (catch-all) qua biểu thức sao (*). Phần tử có dấu sao nhận tất cả giá trị không khớp với phần tử khác.
largest, second_largest, *rest_of_numbers = random_numbers_descending
print(f"largest: {largest}")
print(f"second_largest: {second_largest}")
print(f"rest_of_numbers: {rest_of_numbers}")
Kết quả:
largest: 17
second_largest: 12
rest_of_numbers: [10, 9, 7, 5, 3, 2, 1, 0]
Dấu sao có thể ở bất kỳ vị trí nào
largest, *rest_of_numbers, smallest = random_numbers_descending
print(f"largest: {largest}")
print(f"rest_of_numbers: {rest_of_numbers}")
print(f"smallest: {smallest}")
Kết quả:
largest: 17
rest_of_numbers: [12, 10, 9, 7, 5, 3, 2, 1]
smallest: 0
*rest_of_numbers, second_smallest, smallest = random_numbers_descending
print(f"rest_of_numbers: {rest_of_numbers}")
print(f"second_smallest: {second_smallest}")
print(f"smallest: {smallest}")
Kết quả:
rest_of_numbers: [17, 12, 10, 9, 7, 5, 3, 2]
second_smallest: 1
smallest: 0
Quy tắc quan trọng
- Phải có ít nhất một phần tử bắt buộc (required part) khi dùng dấu sao, nếu không sẽ lỗi
SyntaxError. - Không thể dùng nhiều biểu thức sao ở cùng một cấp độ giải nén (single-level).
- Nhưng có thể dùng nhiều dấu sao ở các cấp độ khác nhau (multi-level unpacking).
Ví dụ đa cấp (nested unpacking)
player_grandslame_and_atptitles = {
'Federer': (20, 103),
'Nadal': (20, 84),
}
((player1, (grandslam1, *atptitles1)), (player2, (grandslam2, *atptitles2))) = player_grandslame_and_atptitles.items()
print(f'Player - {player1} Have acheived {grandslam1} grandslams and , {atptitles1} atp tour titles')
print(f'Player - {player2} Have acheived {grandslam2} grandslams and , {atptitles2} atp tour titles')
Kết quả:
Player - Federer Have acheived 20 grandslams and , [103] atp tour titles
Player - Nadal Have acheived 20 grandslams and , [84] atp tour titles
Đặc điểm của biểu thức sao
- Luôn trở thành instance của
list. - Nếu không có phần tử dư, phần catch-all là list rỗng
[]. - Rất hữu ích khi xử lý chuỗi biết trước có ít nhất N phần tử.
random_numbers = [0, 1]
first, second, *rest = random_numbers
print(first, second, rest) # (0, 1, [])