元組(Tuple)#

元組(Tuple)與串列相似,可以儲存多個有序的元素,但 建立後不能修改 (不可變,immutable):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 建立元組
t1 = (1, 2, 3)
t2 = ("apple", "banana", "cherry")
t3 = (1, "hello", 3.14, True)  # 可混合型別

# 單一元素的元組:必須加逗號!
single = (42,)
print(type(single))   # <class 'tuple'>

# 沒有逗號只是括號,不是 tuple
not_tuple = (42)
print(type(not_tuple))  # <class 'int'>

# 也可以不用括號
t4 = 1, 2, 3
print(type(t4))  # <class 'tuple'>

存取與查詢#

元組支援大部分 不修改 的串列操作:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
t = (10, 20, 30, 40, 50)

# 索引與切片
print(t[0])      # 10
print(t[-1])     # 50
print(t[1:4])    # (20, 30, 40)

# 查詢
print(30 in t)        # True
print(t.count(20))    # 1
print(t.index(30))    # 2
print(len(t))         # 5

# 迭代
for item in t:
    print(item)

解包(Unpacking)#

元組最實用的特性之一是可以直接解包到多個變數:

1
2
3
4
t = (10, 20, 30, 40, 50)

a, b, c, d, e = t
print(a, b, c)  # 10 20 30

星號解包#

1
2
3
4
5
6
7
8
9
# 剩餘元素收集到串列
first, *rest = (1, 2, 3, 4, 5)
print(first)  # 1
print(rest)   # [2, 3, 4, 5]

first, *middle, last = (1, 2, 3, 4, 5)
print(first)   # 1
print(middle)  # [2, 3, 4]
print(last)    # 5

交換兩個變數#

利用元組解包,可以不需要暫存變數就完成交換:

1
2
3
x, y = 10, 20
x, y = y, x
print(x, y)  # 20 10

元組 vs 串列#

特性元組 tuple串列 list
是否可修改否(不可變)是(可變)
語法(1, 2, 3)[1, 2, 3]
可做字典的 key
記憶體用量較少較多
適合情境固定資料、多值回傳動態增減的資料

何時使用元組?#

固定不變的資料#

1
2
3
# 座標、RGB 顏色等語意上不應該被修改的資料
position = (25.0, 121.5)   # 緯度、經度
color = (255, 128, 0)      # RGB 值

函式回傳多個值#

函式 return 多個值時,實際上回傳的就是 tuple:

1
2
3
4
5
6
7
8
9
def min_max(numbers):
    return min(numbers), max(numbers)

lo, hi = min_max([3, 1, 4, 1, 5, 9])
print(lo, hi)  # 1 9

# 確認回傳型別
result = min_max([3, 1, 4])
print(type(result))  # <class 'tuple'>

作為字典的 key#

因為 tuple 不可變,所以可以雜湊(hashable),可以當字典的 key;串列則不行:

1
2
3
4
5
6
7
8
locations = {
    (25.0478, 121.5319): "台北車站",
    (22.6273, 120.3014): "高雄車站",
}
print(locations[(25.0478, 121.5319)])  # 台北車站

# 以下會報錯
# bad = {[1, 2]: "value"}  # ❌ TypeError: unhashable type: 'list'

記憶體效率#

元組比串列佔用 更少記憶體 ,迭代速度也略快:

1
2
3
4
5
6
7
import sys

lst = [1, 2, 3, 4, 5]
tup = (1, 2, 3, 4, 5)

print(sys.getsizeof(lst))  # 88(bytes,較多)
print(sys.getsizeof(tup))  # 72(bytes,較少)

常用技巧#

元組轉串列、串列轉元組#

1
2
3
4
5
t = (1, 2, 3)
lst = list(t)   # 轉成串列(可修改)
lst.append(4)
t2 = tuple(lst)  # 再轉回元組
print(t2)  # (1, 2, 3, 4)

用 zip() 建立元組串列#

1
2
3
4
5
6
7
8
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]

pairs = list(zip(names, scores))
print(pairs)  # [('Alice', 85), ('Bob', 92), ('Charlie', 78)]

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

具名元組(namedtuple)#

當元組欄位較多時,可用 namedtuple 讓程式碼更易讀:

1
2
3
4
5
6
7
8
from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)

print(p.x, p.y)    # 3 4(可用名稱存取)
print(p[0], p[1])  # 3 4(也可用索引)
print(p)           # Point(x=3, y=4)