ข้ามไปยังเนื้อหาหลัก
Editor

ทูเพิลใน Python: ข้อมูลที่แก้ไขไม่ได้ ใช้เมื่อไรและทำไม

เริ่มต้น20 นาที5 แบบฝึกหัด60 XP

บทเรียนนี้แปลจากต้นฉบับภาษาอังกฤษRead in EnglishLeer en españolЧитать на русскомLer em portuguêsแจ้งข้อผิดพลาดในการแปล

0/5 แบบฝึกหัด

ลองนึกถึงพิกัด GPS ตำแหน่งอย่าง (40.7128, -74.0060) คือเมืองนิวยอร์ก ถ้าคุณเผลอเปลี่ยนตัวเลขตัวใดตัวหนึ่ง ตำแหน่งนั้นจะชี้ไปที่อื่นโดยสิ้นเชิง ข้อมูลบางอย่างไม่ควรเปลี่ยนเลยหลังจากสร้างขึ้นมาแล้ว

วันที่ก็เช่นกัน วันที่ 1 มกราคม 2025 เป็นข้อเท็จจริงที่ตายตัว คุณคงไม่อยากให้โค้ดเผลอเปลี่ยนวันที่นั้นเป็นวันที่ 37 กุมภาพันธ์ เมื่อข้อมูลต้องถูกล็อกไว้ไม่ให้เปลี่ยน Python มี ทูเพิล (tuple) ไว้ให้

ทูเพิลหน้าตาแทบเหมือนลิสต์ทุกอย่าง แต่มีข้อแตกต่างสำคัญหนึ่งข้อ: เมื่อสร้างทูเพิลแล้ว คุณ เปลี่ยนแปลงมันไม่ได้ ไม่มีการเพิ่ม ลบ หรือสลับสมาชิก ในบทเรียนนี้ คุณจะได้เรียนรู้ว่าทำไมข้อจำกัดนี้จึงเป็นจุดแข็งที่ทรงพลัง

วิธีสร้างทูเพิลใน Python

คุณสร้างทูเพิลได้ด้วยการใส่สมาชิกไว้ใน วงเล็บ () แล้วคั่นด้วยเครื่องหมายจุลภาค (comma) คุณยังสร้างทูเพิลโดยไม่ใส่วงเล็บก็ได้ เพราะสิ่งที่ทำให้เป็นทูเพิลจริงๆ คือเครื่องหมายจุลภาค

การสร้างทูเพิล
# Tuple with parentheses
coordinates = (40.7128, -74.0060)
print(coordinates)
# Tuple without parentheses (commas do the work)
colors = 'red', 'green', 'blue'
print(colors)
# Single-item tuple NEEDS a trailing comma
single = (42,)
print(single) # (42,)
print(type(single)) # <class 'tuple'>
ผลลัพธ์
(40.7128, -74.006)
('red', 'green', 'blue')
(42,)
<class 'tuple'>
ทูเพิลสมาชิกตัวเดียว กับนิพจน์ในวงเล็บ
# This is NOT a tuple
not_a_tuple = (42)
print(type(not_a_tuple)) # <class 'int'>
# This IS a tuple
is_a_tuple = (42,)
print(type(is_a_tuple)) # <class 'tuple'>
# Empty tuple
empty = ()
print(empty) # ()
print(len(empty)) # 0
ผลลัพธ์
<class 'int'>
<class 'tuple'>
()
0

คุณยังแปลงลำดับข้อมูล (sequence) แบบอื่นให้เป็นทูเพิลได้ด้วยคอนสตรักเตอร์ tuple() วิธีนี้สะดวกเมื่อคุณมีลิสต์และอยากแช่แข็งมันไว้ไม่ให้ใครแก้ไขได้

การใช้คอนสตรักเตอร์ tuple()
# Convert a list to a tuple
fruit_list = ['apple', 'banana', 'cherry']
fruit_tuple = tuple(fruit_list)
print(fruit_tuple) # ('apple', 'banana', 'cherry')
# Convert a string to a tuple of characters
letters = tuple('hello')
print(letters) # ('h', 'e', 'l', 'l', 'o')
ผลลัพธ์
('apple', 'banana', 'cherry')
('h', 'e', 'l', 'l', 'o')

การเข้าถึงและการตัดช่วงสมาชิกของทูเพิล

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

การใช้ดัชนีกับทูเพิล
months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun')
# Positive indexing
print(months[0]) # Jan
print(months[3]) # Apr
# Negative indexing
print(months[-1]) # Jun
print(months[-2]) # May
# Length
print(len(months)) # 6
ผลลัพธ์
Jan
Apr
Jun
May
6

การตัดช่วง (slicing) ก็ทำงานแบบเดียวกัน คุณดึงบางส่วนของทูเพิลออกมาได้ด้วย tuple[start:end] ผลลัพธ์คือทูเพิลใหม่

การตัดช่วงทูเพิล
months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun')
# Slice from index 1 to 4 (not including 4)
print(months[1:4]) # ('Feb', 'Mar', 'Apr')
# First three
print(months[:3]) # ('Jan', 'Feb', 'Mar')
# Last two
print(months[-2:]) # ('May', 'Jun')
# Every other month
print(months[::2]) # ('Jan', 'Mar', 'May')
ผลลัพธ์
('Feb', 'Mar', 'Apr')
('Jan', 'Feb', 'Mar')
('May', 'Jun')
('Jan', 'Mar', 'May')

แต่นี่คือจุดที่ทูเพิลต่างจากลิสต์ ถ้าคุณพยายามเปลี่ยนสมาชิกตัวใด Python จะแจ้ง TypeError ทูเพิล เปลี่ยนแปลงไม่ได้ (immutable) คือแก้ไขไม่ได้หลังจากสร้างแล้ว

ทูเพิลเปลี่ยนแปลงไม่ได้
colors = ('red', 'green', 'blue')
# This works fine - reading
print(colors[0]) # red
# This will CRASH - writing
# colors[0] = 'yellow' # TypeError: 'tuple' object does not support item assignment
# Uncomment the line above and run it to see the error!
ผลลัพธ์
red

การแพ็กและการแตกค่าทูเพิล

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

การแพ็กและการแตกค่า
# Packing - multiple values into one tuple
person = 'Alice', 25, 'Engineer'
print(person) # ('Alice', 25, 'Engineer')
# Unpacking - one tuple into multiple variables
name, age, job = person
print(name) # Alice
print(age) # 25
print(job) # Engineer
ผลลัพธ์
('Alice', 25, 'Engineer')
Alice
25
Engineer

จำนวนตัวแปรทางซ้ายต้องเท่ากับจำนวนสมาชิกในทูเพิล ถ้าไม่เท่ากัน Python จะแจ้ง ValueError

การใช้การแตกค่าแบบคลาสสิกคือ การสลับค่าตัวแปรสองตัว โดยไม่ต้องใช้ตัวแปรชั่วคราว ภาษาอื่นส่วนใหญ่ต้องใช้สามบรรทัด แต่ Python ทำได้ในบรรทัดเดียว

สลับค่าตัวแปรด้วยการแตกค่าทูเพิล
a = 10
b = 20
print(f'Before: a={a}, b={b}')
# Swap using tuple unpacking
a, b = b, a
print(f'After: a={a}, b={b}')
ผลลัพธ์
Before: a=10, b=20
After:  a=20, b=10

คุณยังใช้ดอกจัน * เพื่อเก็บสมาชิกที่เหลือตอนแตกค่าได้ด้วย เรียกว่า การแตกค่าแบบขยาย (extended unpacking) ซึ่งจะได้สมาชิกที่เหลือออกมาเป็นลิสต์

การแตกค่าแบบขยายด้วยตัวดำเนินการดอกจัน
scores = (95, 87, 72, 68, 91)
# Grab the first, last, and everything in between
first, *middle, last = scores
print(first) # 95
print(middle) # [87, 72, 68]
print(last) # 91
ผลลัพธ์
95
[87, 72, 68]
91
การแตกค่าทูเพิลในลูป for
students = [
('Alice', 95),
('Bob', 87),
('Charlie', 72),
]
for name, score in students:
print(f'{name} scored {score}')
ผลลัพธ์
Alice scored 95
Bob scored 87
Charlie scored 72

ทูเพิลกับลิสต์: ควรใช้แบบไหนเมื่อไร

ถ้าทูเพิลเป็นแค่ลิสต์ที่แก้ไขไม่ได้ แล้วจะใช้ไปทำไม มีเหตุผลหนักแน่นสามข้อ: ความปลอดภัย ประสิทธิภาพ และการใช้เป็นคีย์ของดิกชันนารี

ความปลอดภัย: เมื่อข้อมูลไม่ควรเปลี่ยน ทูเพิลช่วยป้องกันการแก้ไขโดยไม่ตั้งใจ พิกัด GPS ค่าสี RGB ระเบียนในฐานข้อมูล สิ่งเหล่านี้เป็นข้อเท็จจริงที่คงที่ ทูเพิลทำให้เจตนาของคุณชัดเจน

ประสิทธิภาพ: ทูเพิลเร็วกว่าลิสต์เล็กน้อยและใช้หน่วยความจำน้อยกว่า สำหรับข้อมูลชุดเล็กๆ แทบไม่มีผล แต่เมื่อมีข้อมูลเป็นล้านรายการ ความต่างก็สะสมจนเห็นได้

คีย์ของดิกชันนารี: ทูเพิลใช้เป็นคีย์ของดิกชันนารีได้เพราะเปลี่ยนแปลงไม่ได้ แต่ลิสต์ใช้ไม่ได้ เรื่องนี้จะสำคัญเมื่อคุณเรียนเรื่องดิกชันนารี

ใช้ลิสต์เมื่อ...
# Data that changes over time
shopping = ['milk', 'eggs']
shopping.append('bread')

# Collections you sort or filter
scores = [85, 92, 78]
scores.sort()
ใช้ทูเพิลเมื่อ...
# Fixed data that shouldn't change
coords = (40.7128, -74.0060)
rgb_red = (255, 0, 0)

# Returning multiple values
def get_name_age():
    return 'Alice', 25

เบื้องหลัง: ทำไมทูเพิลจึงเร็วกว่าลิสต์

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

เปรียบเทียบการใช้หน่วยความจำ
import sys
# Compare memory usage
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
print(f'List size: {sys.getsizeof(my_list)} bytes')
print(f'Tuple size: {sys.getsizeof(my_tuple)} bytes')
ผลลัพธ์
List size:  52 bytes
Tuple size: 40 bytes

ทูเพิลยังรองรับการดำเนินการทุกอย่างของลิสต์ที่ไม่แก้ไขลำดับข้อมูล คุณใช้ count() นับจำนวนครั้งที่ค่าปรากฏ index() หาตำแหน่งของค่า in ตรวจว่ามีค่านั้นอยู่หรือไม่ และ + เพื่อต่อทูเพิลเข้าด้วยกัน

เมธอดและการดำเนินการของทูเพิล
numbers = (1, 2, 3, 2, 4, 2)
# count() - how many times a value appears
print(numbers.count(2)) # 3
# index() - position of first occurrence
print(numbers.index(3)) # 2
# in - membership check
print(4 in numbers) # True
# Concatenation creates a NEW tuple
combined = (1, 2) + (3, 4)
print(combined) # (1, 2, 3, 4)
ผลลัพธ์
3
2
True
(1, 2, 3, 4)

แบบฝึกหัด

ได้เวลาฝึกแล้ว แบบฝึกหัดเหล่านี้ครอบคลุมการสร้างทูเพิล การแตกค่า และความเข้าใจเรื่องการเปลี่ยนแปลงไม่ได้

แบบฝึกหัดที่ 1: สร้างทูเพิลและเข้าถึงสมาชิก
เขียนโค้ด

สร้างทูเพิลชื่อ seasons ที่เก็บชื่อสี่ฤดูเป็นสตริง: 'Spring', 'Summer', 'Fall', 'Winter'

จากนั้นแสดงฤดูแรกและฤดูสุดท้าย บรรทัดละหนึ่งฤดู

ผลลัพธ์ที่ต้องได้:

Spring
Winter
# Create the seasons tuple
# Print the first season
# Print the last season
แบบฝึกหัดที่ 2: ทายผลลัพธ์: ทูเพิลที่มีสมาชิกตัวเดียว
ทายผลลัพธ์

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

a = (5)
b = (5,)
print(type(a).__name__)
print(type(b).__name__)

เขียนคำสั่ง print() สองคำสั่งที่แสดงผลออกมาเหมือนกันทุกตัวอักษร

# Predict the output and write the matching print statements
print("?")
print("?")
แบบฝึกหัดที่ 3: แตกค่าทูเพิล
เขียนโค้ด

มีทูเพิลที่แทนระเบียนข้อมูลนักเรียนให้มา แตกค่าออกเป็นตัวแปรสามตัว: name, age และ grade

จากนั้นแสดงตัวแปรแต่ละตัว บรรทัดละหนึ่งตัว

ผลลัพธ์ที่ต้องได้:

Emma
16
A
student = ('Emma', 16, 'A')
# Unpack the tuple into name, age, grade
# Print each variable
แบบฝึกหัดที่ 4: แก้บั๊ก: การแก้ไขทูเพิล
แก้บั๊ก

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

ผลลัพธ์ที่ต้องได้:

('red', 'yellow', 'blue')
colors = ('red', 'green', 'blue')
colors[1] = 'yellow'
print(colors)
แบบฝึกหัดที่ 5: วนลูปและแตกค่าคะแนนนักเรียน
เขียนโค้ด

คุณมีลิสต์ของทูเพิล แต่ละทูเพิลเก็บชื่อนักเรียนและคะแนน วนลูปผ่านลิสต์ แตกค่าแต่ละทูเพิล แล้วแสดงผลของนักเรียนแต่ละคนในรูปแบบนี้:

Alice: 92
Bob: 85
Charlie: 78
students = [
('Alice', 92),
('Bob', 85),
('Charlie', 78),
]
# Loop through and print each student's result

สรุป: สิ่งที่คุณได้เรียนเกี่ยวกับทูเพิลใน Python

ทบทวนทุกอย่างที่คุณรู้แล้วเกี่ยวกับทูเพิล:

แนวคิดใช้ทำอะไรตัวอย่าง
สร้างทูเพิลเก็บข้อมูลที่คงที่point = (3, 4)
จุลภาคต่อท้ายสร้างทูเพิลสมาชิกตัวเดียวsolo = (42,)
การใช้ดัชนีเข้าถึงตามตำแหน่งpoint[0], point[-1]
การตัดช่วงดึงบางส่วนออกมาmonths[1:4]
การแตกค่าแยกค่าใส่ตัวแปรx, y = point
การแตกค่าแบบขยายเก็บส่วนที่เหลือด้วย *first, *rest = items
count()นับจำนวนครั้งที่ปรากฏt.count(2)
index()หาตำแหน่งt.index(3)
การเปลี่ยนแปลงไม่ได้แก้ไขไม่ได้หลังสร้างแจ้ง TypeError

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

เรียนอะไรต่อ

ในบทเรียนถัดไป ดิกชันนารีใน Python คุณจะได้เรียนวิธีเก็บข้อมูลเป็นคู่คีย์กับค่า (key-value) แทนที่จะเข้าถึงสมาชิกตามตำแหน่ง คุณจะเข้าถึงด้วยชื่อ

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

บทเรียนที่เกี่ยวข้อง

บทเรียนนี้มีประโยชน์หรือไม่