บทนำ
ข้อจำกัดพื้นฐานของ unpacking คือ ต้องรู้ความยาวของ sequence ล่วงหน้า
ปัญหา
random_numbers = [0, 1, 5, 9, 17, 12, 7, 10, 3, 2]
random_numbers_descending = sorted(random_numbers, reverse=True)
# [17, 12, 10, 9, 7, 5, 3, 2, 1, 0]
# พยายาม unpack แค่ 2 ตัวแรก - จะ error
largest, second_largest = random_numbers_descending
# ValueError: too many values to unpack (expected 2)
วิธีเก่า: ใช้ Indexing/Slicing
largest = random_numbers_descending[0] # 17
second_largest = random_numbers_descending[1] # 12
rest_of_numbers = random_numbers_descending[2:] # [10, 9, 7, 5, 3, 2, 1, 0]
วิธีนี้ทำงานได้ แต่โค้ดดู雜乱 (visually noisy) และ error-prone
วิธีที่ดีกว่า: Starred Expression (PEP 3132)
Syntax ดาว (*) รองรับ catch-all unpacking ส่วนที่ไม่ match pattern อื่นจะไปเก็บในตัวแปรที่มี *
ตัวอย่าง 1: ดึง 2 ตัวแรก ที่เหลือไปเก็บใน *rest
largest, second_largest, *rest_of_numbers = random_numbers_descending
print(f"largest: {largest}") # 17
print(f"second_largest: {second_largest}") # 12
print(f"rest_of_numbers: {rest_of_numbers}") # [10, 9, 7, 5, 3, 2, 1, 0]
ตัวอย่าง 2: ดึงตัวแรกและตัวสุดท้าย ที่เหลือไปเก็บใน *rest
largest, *rest_of_numbers, smallest = random_numbers_descending
print(f"largest: {largest}") # 17
print(f"rest_of_numbers: {rest_of_numbers}") # [12, 10, 9, 7, 5, 3, 2, 1]
print(f"smallest: {smallest}") # 0
ตัวอย่าง 3: ดึง 2 ตัวสุดท้าย
*rest_of_numbers, second_smallest, smallest = random_numbers_descending
print(f"rest_of_numbers: {rest_of_numbers}") # [17, 12, 10, 9, 7, 5, 3, 2]
print(f"second_smallest: {second_smallest}") # 1
print(f"smallest: {smallest}") # 0
ข้อจำกัดสำคัญ
- ต้องมี required part อย่างน้อย 1 ตัว - ไม่สามารถใช้
*rest = seqได้ (SyntaxError) - ไม่สามารถมี starred expression หลายตัวในระดับเดียวกัน -
*a, *b, c = seqError - แต่สามารถมีหลาย starred expression ในโครงสร้างหลายระดับ (nested)
ตัวอย่าง Nested Starred Expression
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')
ผลลัพธ์:
Player - Federer Have acheived 20 grandslams and , [103] atp tour titles
Player - Nadal Have acheived 20 grandslams and , [84] atp tour titles
พฤติกรรมของ Starred Expression
- Starred expression เสมอจะกลายเป็น list
- ถ้าไม่มี leftover items จะเป็น empty list
[] - เหมาะสำหรับ sequence ที่รู้ว่ามีอย่างน้อย N องค์ประกอบ
random_numbers = [0, 1]
first, second, *rest = random_numbers
print(first, second, rest) # (0, 1, [])