一個看似簡單的謎題揭示了 Python 最基本的概念之一
在深入解釋之前,我們先來做個小測試。看一下這段 Python 程式碼,預測一下它會輸出什麼:
a = 500
b = a
a = a + 100
list1 = [1, 2]
list2 = list1
list1.append(3)
print(f"b is {b}")
print(f"list2 is {list2}")
您認為輸出結果會是什麼?
A) b is 600
, list2 is [1, 2]
B) b is 500
, list2 is [1, 2, 3]
C) b is 500
, list2 is [1, 2]
D) b is 600
, list2 is [1, 2, 3]
花點時間仔細想想。程式碼看起來很簡單,但其中有一些微妙之處,即使是經驗豐富的開發人員也會犯錯。
當您準備好答案時,請向下滾動...
正確答案是B : b is 500
, list2 is [1, 2, 3]
如果你答對了,太棒了!如果沒有,也不用擔心──這種行為讓許多 Python 開發者感到困惑。理解這一點的關鍵在於一個許多教程都忽略的關鍵概念。
我們程式碼中的不同行為並非隨機或不一致。它們是 Python 處理兩種不同類型物件(可變物件和不可變物件)的邏輯結果。
讓我們一步一步分析到底發生了什麼事。
a = 500
b = a
a = a + 100
Python 實際做的事情如下:
a = 500
:建立一個包含500
整數物件,並指派名稱a
來指向它
b = a
:使b
指向a
指向的同一個500
物件
a = a + 100
:這是關鍵的一行。它計算a + 100
(即600
),建立一個包含600
全新整數物件,並將a
重新賦值給這個新物件。
關鍵在於:整數在 Python 中是不可變的。整數物件一旦建立,就無法變更其值。當你寫a = a + 100
時,Python 不會修改現有的500
物件,而是創造一個新的600
物件。
由於b
從未被重新賦值,它仍然指向原始的500
物件。因此: b is 500
。
list1 = [1, 2]
list2 = list1
list1.append(3)
現在讓我們追蹤清單操作:
list1 = [1, 2]
:建立一個包含[1, 2]
的列表物件,並指派list1
指向它
list2 = list1
:使list2
指向list1
指向的相同列表物件
list1.append(3)
:差別在於-它透過向現有清單物件加入3
來修改它
關鍵見解:清單在 Python 中是可變的。呼叫append()
時,實際上是在修改現有列表物件,而不是建立新物件。
由於list1
和list2
都指向同一個列表物件,並且該對像已被修改,因此兩個名稱現在都指向[1, 2, 3]
。因此: list2 is [1, 2, 3]
。
這個謎題說明了許多開發人員誤解的有關 Python 的一個基本事實:變數是指向物件的名稱,而不是保存值的容器。
可以這樣想:
變數名就像一張寫有名字的便條
物件就像包含實際資料的盒子
任務將姓名標籤貼在盒子上
多個名稱可以指向同一個框
當你理解了這個思考模型,這個神祕程式碼就完全說得通了:
對於不可變物件(整數),操作會建立新的框並移動名稱標籤以指向它們
對於可變物件(清單),操作會修改現有方塊的內容,但指向該方塊的所有名稱標籤保持不變
理解可變性不僅僅是學術層面的——它能防止真正的 bug。想想這個常見的 Python 陷阱:
def add_item(item, target_list=[]):
target_list.append(item)
return target_list
# This doesn't work as expected!
list1 = add_item("first")
list2 = add_item("second") # Oops! list2 is now ["first", "second"]
預設列表[]
是可變的,因此所有函數呼叫共享同一個列表物件。一旦你理解了物體的可變性,這種行為就變得可預測,而不是神秘莫測。
現在您已經知道了秘密,請嘗試預測此程式碼的輸出:
x = "hello"
y = x
x = x + " world"
dict1 = {"key": "value"}
dict2 = dict1
dict1["key"] = "modified"
print(f"y is '{y}'")
print(f"dict2 is {dict2}")
答案: y is 'hello'
, dict2 is {'key': 'modified'}
(字串是不可變的,字典是可變的)。
一旦你了解底層模型,你就會發現 Python 的變數系統非常優雅。變數本身並不包含物件,而是指向物件。指向的物件是否可修改取決於它的可變性。
這個概念解釋了無數乍看之下似乎很神秘的 Python 行為。掌握它,你會發現 Python 程式碼更可預測且易於除錯。
理解可變性只是 Python 眾多優雅概念中的一個,這些概念讓 Python 變得強大。一旦你理解了這個規律,你就會開始在程式碼的任何地方都能辨識它。
還有哪些 Python 謎題困擾著你?在留言區分享你的例子-或許有比你想像的更簡單的解釋!如果你覺得這篇文章有幫助,請關注,了解更多 Python 洞見,揭開程式碼背後的神秘面紗。
Aaron Rose 是tech-reader.blog的軟體工程師和技術作家,也是《像天才一樣思考》一書的作者。
原文出處:https://dev.to/aaron_rose_0787cc8b4775a0/python-mystery-quiz-can-you-crack-this-code-3o53