2019年2月20日 星期三

[Python] 如何做swap()


如題,故事是這樣的,某日久違沒碰Python的我發現自己居然連數值交換 swap() 都做不出來,於是就有了這篇筆記。

我一開始是這樣做的:
def swap(a, b):
    tmp = a
    a = b
    b = a

x = 3
y = 5
swap(x,y)
print(x, y) # 結果印出 x是3  y是5

這樣寫就好像回到剛學程式語言,C語言裡的"call by value" vs "call by reference"時的範例

因為我印象中好像Python變數都是指向object,所以先當作都是 call by reference

結果是x, y值並沒有改變...


直接說答案,使用Python想交換兩變數的值正確簡短的做法可以這麼做:
x = 3
y = 5
x ,y = y, x
print(x, y) # >> 5,3

怎麼跟想的不一樣...於是就去Google啦~



Immutable vs Mutable


首先看看下面的程式碼:
x=2
print("x=",x," id=",id(x))  # >> x=2, id=93973909193040  black
x=3
print("x=",x," id=",id(x))  # >> x=3, id=93973909193016  red
圖解來看其實 x = 2 是將 x 指向了值是 2 的 int 物件,執行到 x = 3 時則改成指向另外值是 3 的 int 物件

這裡Python的 "=" (assign)會讓x指向另一個object,而不能修改內容,這類型的就稱為 immutable (unchangeable in-place ) object,像是 integer、string、tuples

所以下面的程式碼不能利用w修改q值:
q = 1
w = q  # w, q id 是相同的
w = 3
print(q,w)  # q還是1, w則是3


那當然會有mutable (changeable in-place ) object存在,像是 list、dictionary

下面的code就可利用w指向相同的list來修改q值:
q = [1, 2, 3]
w = q
w[0] = 3
print(q)  # >> [3,2,3]

assgin "="對於immutable object不能改value,而是會創造一個新的物件(所以id會不一樣),mutable object則是改value,不需新的物件產生


回到上面的swap()為什麼不可行
def swap(a, b):
    tmp = a
    a = b
    b = a

x = 3
y = 5
swap(x,y)
print(x, y) # 結果印出 x是3  y是5
其實swap裡就只是幾個變數tmp, a, b改對到x對到的int物件或y對到的int物件,根本不會動到x, y 對應的物件


補充


另外,在mutable object的狀況時要怎麼只存值呢?

像下面的code我們保存 t 這個 list 進 tt list裡,但之後若修改 t 連帶的也動到 tt 裡的值 (因為其實它們存取是同一物件) (這大概也是寫python code一開始容易不小心犯的錯):
t = [1,2,3]
tt = []
tt.extend(t)
t[0] = 2
print(tt)  # [2,2,3]

若只想存值,而非要存物件,可以這麼寫:
t = [1,2,3]
tt = []
tt.extend(t[:])
t[0] = 2
print(tt)  # [1,2,3]
如此就算修改t也不會讓tt內的值改變了,或是可以使用 copy() 函式之類的,這通常就是會只複製值



1 則留言:

  1. 你的swap function 寫錯啦, 最後一個應該寫成b=tmp 才對, 不是b=a, 寫b=a 的話, 上一行a=b, b=a 會變成 a,b 都變成 b
    def swap(a, b):
    tmp = a
    a = b
    b = a

    回覆刪除