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

Unpacking ใน Python: ตัวแปรมีดาว สลับค่า และแยกข้อมูลซ้อน

ปานกลาง20 นาที5 แบบฝึกหัด70 XP

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

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

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

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

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

การแยกค่าแบบพื้นฐานทำงานอย่างไร

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

แยกค่าจากทูเพิลและลิสต์แบบพื้นฐาน
# Unpacking a tuple
coordinates = (10, 20, 30)
x, y, z = coordinates
print(x) # 10
print(y) # 20
print(z) # 30
# Unpacking a list
colors = ['red', 'green', 'blue']
first, second, third = colors
print(first) # red
print(second) # green
print(third) # blue
ผลลัพธ์
10
20
30
red
green
blue

ถ้าไม่ใช้การแยกค่า คุณต้องดึงสมาชิกแต่ละตัวด้วยดัชนี การแยกค่าทำให้โค้ดสั้นลงและอ่านง่ายขึ้นมาก

ไม่ใช้การแยกค่า (ยืดยาว)
point = (10, 20, 30)
x = point[0]
y = point[1]
z = point[2]
print(x, y, z)
ใช้การแยกค่า (กระชับ)
point = (10, 20, 30)
x, y, z = point
print(x, y, z)

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

แยกค่าโดยไม่ใช้วงเล็บ
# Direct unpacking (no parentheses needed)
name, age, city = 'Alice', 25, 'Paris'
print(name) # Alice
print(age) # 25
print(city) # Paris
# This works because Python sees commas and creates a tuple
print(type(('Alice', 25, 'Paris'))) # <class 'tuple'>
ผลลัพธ์
Alice
25
Paris
<class 'tuple'>

วิธีสลับค่าตัวแปรในบรรทัดเดียว

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

สลับค่าตัวแปรสองตัว
a = 'hello'
b = 'world'
# Swap in one line!
a, b = b, a
print(a) # world
print(b) # hello
ผลลัพธ์
world
hello

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

ภาษาอื่น (ต้องใช้ตัวแปรชั่วคราว)
a = 1
b = 2
temp = a
a = b
b = temp
print(a, b)  # 2 1
Python (บรรทัดเดียว)
a = 1
b = 2
a, b = b, a
print(a, b)  # 2 1

คุณสลับค่าตัวแปรสามตัวหรือมากกว่าได้ด้วยวิธีเดียวกัน Python จัดการทั้งหมดในขั้นตอนเดียว

หมุนค่าตัวแปรสามตัว
# Rotate three variables
a, b, c = 1, 2, 3
print(f'Before: a={a}, b={b}, c={c}')
a, b, c = b, c, a
print(f'After: a={a}, b={b}, c={c}')
ผลลัพธ์
Before: a=1, b=2, c=3
After:  a=2, b=3, c=1

นิพจน์แบบมีดาว (*rest) คืออะไร

บางครั้งคุณไม่รู้แน่ชัดว่ากลุ่มข้อมูลมีสมาชิกกี่ตัว หรือสนใจแค่บางตัวเท่านั้น นิพจน์แบบมีดาว (starred expression) เช่น *variable จะเก็บสมาชิกที่เหลือทั้งหมดไว้ในลิสต์

นิพจน์แบบมีดาวเก็บสมาชิกที่เหลือ
# Capture the first item and everything else
numbers = [1, 2, 3, 4, 5]
first, *rest = numbers
print(first) # 1
print(rest) # [2, 3, 4, 5]
# Capture the last item and everything before it
*beginning, last = numbers
print(beginning) # [1, 2, 3, 4]
print(last) # 5
ผลลัพธ์
1
[2, 3, 4, 5]
[1, 2, 3, 4]
5

คุณวางดาวไว้ตรงกลางก็ได้ เหมาะมากเมื่อคุณรู้ว่าต้องการสมาชิกตัวแรกและตัวสุดท้าย แต่อยากข้ามทุกตัวที่อยู่ระหว่างกลาง

ดาวอยู่ตรงกลาง
scores = [95, 80, 75, 90, 85, 70, 88]
# Get the first, last, and everything in between
first, *middle, last = scores
print(f'First: {first}') # 95
print(f'Middle: {middle}') # [80, 75, 90, 85, 70]
print(f'Last: {last}') # 88
ผลลัพธ์
First: 95
Middle: [80, 75, 90, 85, 70]
Last: 88
ดาวที่ไม่ได้สมาชิกเลย และการใช้กับสตริง
# Star captures zero items (still a list)
a, b, *rest = [10, 20]
print(a) # 10
print(b) # 20
print(rest) # []
# Star from a string
first, *middle, last = 'Hello'
print(first) # H
print(middle) # ['e', 'l', 'l']
print(last) # o
ผลลัพธ์
10
20
[]
H
['e', 'l', 'l']
o

วิธีใช้การแยกค่าในลูป for

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

แยกค่าทูเพิลในลูป for
# List of (name, age) tuples
students = [
('Alice', 16),
('Bob', 15),
('Charlie', 17),
]
# Unpack each tuple in the loop
for name, age in students:
print(f'{name} is {age} years old')
ผลลัพธ์
Alice is 16 years old
Bob is 15 years old
Charlie is 17 years old

รูปแบบนี้ใช้บ่อยมากกับ enumerate() และ dict.items() ทั้งสองคืนค่าเป็นทูเพิล และการแยกค่าทำให้โค้ดอ่านง่ายขึ้นมาก

แยกค่าด้วย enumerate() และ dict.items()
# enumerate() returns (index, value) tuples
fruits = ['apple', 'banana', 'cherry']
for i, fruit in enumerate(fruits):
print(f'{i}: {fruit}')
print()
# dict.items() returns (key, value) tuples
ages = {'Alice': 16, 'Bob': 15, 'Charlie': 17}
for name, age in ages.items():
print(f'{name} -> {age}')
ผลลัพธ์
0: apple
1: banana
2: cherry

Alice -> 16
Bob -> 15
Charlie -> 17

วิธีแยกค่าจากโครงสร้างข้อมูลที่ซ้อนกัน

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

แยกค่าซ้อนกันด้วยวงเล็บ
# A tuple containing a nested tuple
record = ('Alice', (95, 87, 92))
# Nested unpacking
name, (score1, score2, score3) = record
print(f'{name}: {score1}, {score2}, {score3}')
ผลลัพธ์
Alice: 95, 87, 92

วิธีนี้ใช้ได้ทุกระดับความลึก คุณยังรวมการแยกค่าแบบซ้อนเข้ากับนิพจน์แบบมีดาวได้ด้วย: name, (first, *others) = ('Alice', (95, 87, 92)) จะเก็บ 95 ไว้ใน first และ [87, 92] ไว้ใน others

แยกค่าซ้อนกันในลูป
# List of students with (name, (math, science, english))
students = [
('Alice', (95, 87, 92)),
('Bob', (78, 85, 90)),
('Charlie', (88, 92, 76)),
]
for name, (math, science, english) in students:
avg = (math + science + english) / 3
print(f'{name}: average = {avg:.1f}')
ผลลัพธ์
Alice: average = 91.3
Bob: average = 84.3
Charlie: average = 85.3

ข้อผิดพลาดที่พบบ่อยในการแยกค่า

เมื่อจับหลักได้แล้ว การแยกค่าก็เข้าใจง่าย แต่มีกับดักบางอย่างที่ผู้เริ่มต้นมักพลาด

ข้อผิดพลาดที่พบบ่อยในการแยกค่า
# Mistake 1: Forgetting parentheses in nested unpacking
# Wrong: name, x, y = ('Alice', (10, 20)) -> ValueError!
# Right:
name, (x, y) = ('Alice', (10, 20))
print(name, x, y)
# Mistake 2: Unpacking a single-item tuple
# You need the comma to make it a tuple!
value, = (42,) # Note the comma after 42
print(value) # 42
# Mistake 3: Forgetting that * always creates a list
first, *rest = 'AB'
print(type(rest)) # <class 'list'>, not str!
ผลลัพธ์
Alice 10 20
42
<class 'list'>

แบบฝึกหัด

แยกค่าพิกัด
เขียนโค้ด

แยกค่าทูเพิล point ใส่ตัวแปรสามตัว: x, y และ z จากนั้นแสดงค่าทั้งสามในบรรทัดเดียวโดยคั่นด้วยช่องว่าง โดยใช้ print(x, y, z)

point = (7, 14, 21)
# Unpack into x, y, z and print them
สลับค่าตัวแปรสองตัว
เขียนโค้ด

ตัวแปร first และ second เก็บค่าไว้ผิดตัว ให้สลับค่าด้วยรูปแบบการแยกค่าของ Python (บรรทัดเดียว ไม่ใช้ตัวแปรชั่วคราว) แล้วแสดงค่าทั้งสอง

first = 'goodbye'
second = 'hello'
# Swap first and second in one line
print(first)
print(second)
แยกตัวแรกกับส่วนที่เหลือด้วยดาว
เขียนโค้ด

ใช้นิพจน์แบบมีดาวแยกค่าลิสต์ numbers ใส่ head (สมาชิกตัวแรก) และ tail (ที่เหลือทั้งหมด) แล้วแสดงทั้งสองค่าคนละบรรทัด

numbers = [10, 20, 30, 40, 50]
# Unpack into head and tail using *
ทายผลลัพธ์ของการแยกค่า
ทายผลลัพธ์

โค้ดนี้แสดงอะไร? ลองคิดว่าดาวเก็บอะไรไว้ และกลายเป็นข้อมูลชนิดใด

a, *b, c = [1, 2, 3, 4, 5, 6]
print(a)
print(b)
print(c)

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

# Predict the output and write the matching print statements
print("?")
print("?")
print("?")
แยกค่าข้อมูลนักเรียน
เขียนโค้ด

คุณมีลิสต์ของข้อมูลนักเรียน แต่ละรายการเป็นทูเพิลรูปแบบ (name, (math_score, english_score)) ใช้การแยกค่าแบบซ้อนในลูป for เพื่อคำนวณและแสดงคะแนนเฉลี่ยของนักเรียนแต่ละคน

แสดงแต่ละบรรทัดในรูปแบบ Name: average โดยปัดค่าเฉลี่ยให้เหลือทศนิยม 1 ตำแหน่งด้วย :.1f

students = [
('Alice', (90, 80)),
('Bob', (70, 90)),
('Charlie', (85, 95)),
]
# Loop with nested unpacking and print averages

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

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