Python ทูเพิล (Tuple) และ Unpacking



ทูเพิล (Tuple) คือคอลเลกชันที่คล้ายกับลิสต์ (List) แต่มีความแตกต่างสำคัญคือ เมื่อสร้างแล้วจะไม่สามารถเพิ่ม ลบ หรือเปลี่ยนสมาชิกได้

สร้างทูเพิล

ใช้วงเล็บกลม () แทนวงเล็บเหลี่ยม

point = (10, 20)
rgb = (255, 128, 0)
person = ("สมชาย", 25, "กรุงเทพ")

จริง ๆ วงเล็บไม่บังคับ แค่มีจุลภาคก็เป็นทูเพิลแล้ว

point = 10, 20
print(type(point))   # <class 'tuple'>

ระวังทูเพิลตัวเดียว ต้องมีจุลภาคต่อท้าย ไม่งั้นมันเป็นแค่ค่าในวงเล็บ

a = (5)      # นี่คือ int 5
b = (5,)     # นี่คือ tuple ที่มีสมาชิกตัวเดียว
print(type(a), type(b))   # <class 'int'> <class 'tuple'>

เข้าถึงสมาชิก

การเข้าถึงสมาชิกของทูเพิลทำได้คล้ายกับลิสต์ โดยใช้ index ทั้งค่าบวกและค่าลบ รวมถึงสามารถใช้ len() และวนลูปด้วย for ได้

person = ("สมชาย", 25, "กรุงเทพ")

print(person[0])    # สมชาย
print(person[-1])   # กรุงเทพ
print(len(person))  # 3

for item in person:
    print(item)
numbers = (10, 20, 30, 40, 50)

print(numbers[1:4])   # (20, 30, 40)

แก้ไม่ได้ แปลว่าอะไร

point = (10, 20)
point[0] = 99   # TypeError: 'tuple' object does not support item assignment

คำถามคือ แล้วจะใช้ทำไมถ้าแก้ไม่ได้ คำตอบคือ ความแก้ไม่ได้เป็นข้อดีในหลายสถานการณ์

  • ข้อมูลที่ไม่ควรเปลี่ยน เช่น พิกัด, ค่าสี RGB, วันเดือนปีเกิด ใช้ทูเพิลแล้วมั่นใจว่าไม่มีโค้ดส่วนไหนไปแก้โดยไม่ตั้งใจ
  • เร็วกว่าและกินหน่วยความจำน้อยกว่า ลิสต์เล็กน้อย
  • ทูเพิลสามารถใช้เป็นคีย์ของ dict ได้ หากสมาชิกภายในเป็นข้อมูลที่เหมาะสม เช่น ตัวเลขหรือข้อความ (ลิสต์ไม่สามารถใช้เป็นคีย์ได้)
locations = {
    (13.75, 100.50): "กรุงเทพ",
    (18.79, 98.98): "เชียงใหม่",
}
print(locations[(13.75, 100.50)])   # กรุงเทพ

Unpacking: แกะค่าออกมาทีเดียว

นี่คือของเด็ดที่ทำให้โค้ด Python อ่านสวย เอาสมาชิกในทูเพิล (หรือลิสต์) มาใส่ตัวแปรหลายตัวพร้อมกัน

person = ("สมชาย", 25, "กรุงเทพ")

name, age, city = person

print(name)   # สมชาย
print(age)    # 25
print(city)   # กรุงเทพ

จำนวนตัวแปรทางซ้ายต้องตรงกับจำนวนสมาชิกที่ต้องการ unpack ไม่เช่นนั้นจะเกิด ValueError

สลับค่าตัวแปรแบบไม่ต้องมีตัวแปรพัก

ภาษาอื่นต้องสร้างตัวแปร temp แต่ Python ทำได้บรรทัดเดียว

a = 1
b = 2
a, b = b, a
print(a, b)   # 2 1

รับหลายค่าจากฟังก์ชัน

ใน Python เราสามารถเขียนฟังก์ชันให้คืนค่าหลายค่าได้ โดยค่าที่คั่นด้วยจุลภาคจะถูกรวมเป็นทูเพิล ซึ่งสามารถใช้ unpacking แยกออกเป็นหลายตัวแปรได้

def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 8, 1, 9, 3])
print(low, high)   # 1 9

เก็บส่วนที่เหลือด้วย *

ใส่ * หน้าตัวแปรตัวไหน มันจะกวาดสมาชิกที่เหลือมาเป็นลิสต์

scores = (90, 85, 78, 92, 88)

first, *rest = scores
print(first)   # 90
print(rest)    # [85, 78, 92, 88]

first, *middle, last = scores
print(first, last)   # 90 88
print(middle)        # [85, 78, 92]

Unpacking ในลูป

เวลาวนลิสต์ของทูเพิล แกะออกมาใช้ในหัว for ได้เลย อ่านง่ายกว่าการใช้ index

students = [
    ("สมชาย", 85),
    ("สมหญิง", 92),
    ("สมศรี", 78),
]

for name, score in students:
    print(f"{name}: {score}")

จับคู่กับ enumerate() ที่เราใช้มาตลอด จริง ๆ มันก็คืนทูเพิล (index, value) มาให้เรา unpack นั่นเอง

แปลงไปมาระหว่าง list กับ tuple

t = (1, 2, 3)
lst = list(t)      # [1, 2, 3]
lst.append(4)
t = tuple(lst)     # (1, 2, 3, 4)

หากต้องการเปลี่ยนข้อมูลในทูเพิล สามารถสร้างข้อมูลใหม่โดยแปลงทูเพิลเป็นลิสต์ แก้ไขข้อมูล แล้วแปลงกลับเป็นทูเพิลอีกครั้ง

สรุป

  • ทูเพิลเหมือนลิสต์แต่แก้ไขไม่ได้ สร้างด้วย () หรือแค่ใส่จุลภาค
  • ใช้กับข้อมูลที่ไม่ควรเปลี่ยน และใช้เป็นคีย์ของ dict ได้
  • Unpacking (a, b, c = tuple) ทำให้แกะค่า สลับตัวแปร และรับค่าหลายตัวจากฟังก์ชันได้สวยงาม
  • *rest กวาดสมาชิกที่เหลือมาเป็นลิสต์

บทถัดไปเป็นเซ็ต (Set) คอลเลกชันที่ไม่เก็บค่าซ้ำ และทำงานแบบเซ็ตในคณิตศาสตร์ได้