Python 多變量賦值問(wèn)題小結(jié)
今天在刷鏈表反轉(zhuǎn)題的時(shí)候,遇到了兩段看起來(lái)幾乎一樣的代碼,結(jié)果一個(gè)能正確反轉(zhuǎn)鏈表,一個(gè)卻不行。仔細(xì)研究后發(fā)現(xiàn),問(wèn)題出在 Python 的多變量賦值順序上 —— 這個(gè)平時(shí)沒(méi)太在意的細(xì)節(jié),在操作鏈表指針時(shí)居然能造成這么大的影響。記錄一下我的分析過(guò)程,免得以后再踩類似的坑。
問(wèn)題背景:兩段 “相似” 的反轉(zhuǎn)代碼
先看這兩段代碼,都是用迭代法反轉(zhuǎn)單鏈表:
代碼 1(能正確反轉(zhuǎn)):
def reverseList(head):
last = None
while head:
# 關(guān)鍵賦值行
last, head.next, head = head, last, head.next
return last
代碼 2(無(wú)法正確反轉(zhuǎn)):
def reverseList(head):
last = None
while head:
# 關(guān)鍵賦值行(順序不同)
head, head.next, last = head.next, last, head
return last
第一眼看上去,只是左側(cè)變量的賦值順序變了,右側(cè)的值好像還是那幾個(gè)。但實(shí)際運(yùn)行時(shí),代碼 1 能得到正確的反轉(zhuǎn)鏈表,代碼 2 卻會(huì)返回錯(cuò)誤結(jié)果(比如鏈表斷裂、部分節(jié)點(diǎn)丟失)。這到底是為什么?
核心原因:Python 多變量賦值的 “秘密”
在 Python 里,多變量賦值的執(zhí)行邏輯是 “先計(jì)算右側(cè)所有表達(dá)式的值,再一次性賦值給左側(cè)變量”。也就是說(shuō),右側(cè)的值都是基于賦值前的原始狀態(tài)計(jì)算的,不會(huì)被左側(cè)的中間賦值影響。
但這一點(diǎn),需要注意的是 “=”右側(cè)是獲取值,所以可以理解為完全并行執(zhí)行的。但是左側(cè)是改變值,這就意味著是會(huì)順序影響
逐行分析:兩段代碼的執(zhí)行差異
我們用一個(gè)簡(jiǎn)單的鏈表1->2->3來(lái)模擬執(zhí)行過(guò)程,看看兩段代碼的區(qū)別。
代碼 1 的執(zhí)行邏輯(正確)
關(guān)鍵賦值行:last, head.next, head = head, last, head.next
拆解步驟(每次循環(huán)):
- 先算右側(cè)值(基于當(dāng)前原始狀態(tài)):
- 第一個(gè)值:
head(當(dāng)前節(jié)點(diǎn),比如第一輪是 1) - 第二個(gè)值:
last(上一個(gè)節(jié)點(diǎn),初始是 None) - 第三個(gè)值:
head.next(下一個(gè)節(jié)點(diǎn),第一輪是 2)
- 再給左側(cè)賦值:
last= 第一個(gè)值(當(dāng)前節(jié)點(diǎn) 1)→ 現(xiàn)在 last 指向 1head.next= 第二個(gè)值(原 last,即 None)→ 節(jié)點(diǎn) 1 的 next 指向 None(完成反轉(zhuǎn)第一步)head= 第三個(gè)值(下一個(gè)節(jié)點(diǎn) 2)→ 移動(dòng) head 到下一個(gè)節(jié)點(diǎn),繼續(xù)循環(huán)
整個(gè)過(guò)程中,“反轉(zhuǎn)當(dāng)前節(jié)點(diǎn)指針” 和 “移動(dòng) head 到下一個(gè)節(jié)點(diǎn)” 是基于原始值操作的,互不干擾。比如不會(huì)因?yàn)?head 移動(dòng)了,導(dǎo)致當(dāng)前節(jié)點(diǎn)的指針沒(méi)反轉(zhuǎn)。
代碼 2 的執(zhí)行邏輯(錯(cuò)誤)
關(guān)鍵賦值行:head, head.next, last = head.next, last, head
同樣用1->2->3模擬:
- 先算右側(cè)值(基于當(dāng)前原始狀態(tài)):
- 第一個(gè)值:
head.next(下一個(gè)節(jié)點(diǎn) 2) - 第二個(gè)值:
last(初始 None) - 第三個(gè)值:
head(當(dāng)前節(jié)點(diǎn) 1)
- 再給左側(cè)賦值:
head= 第一個(gè)值(下一個(gè)節(jié)點(diǎn) 2)→ 此時(shí) head 已經(jīng)指向 2 了head.next= 第二個(gè)值(原 last,即 None)→ 注意!這里的 head 已經(jīng)是 2 了,所以實(shí)際是把節(jié)點(diǎn) 2 的 next 改成了 Nonelast= 第三個(gè)值(原 head,即節(jié)點(diǎn) 1)→ last 指向 1
這就出問(wèn)題了:原本應(yīng)該反轉(zhuǎn) “當(dāng)前節(jié)點(diǎn) 1 的指針”,結(jié)果因?yàn)橄纫苿?dòng)了 head 到 2,導(dǎo)致實(shí)際修改的是 “節(jié)點(diǎn) 2 的指針”。節(jié)點(diǎn) 1 的指針根本沒(méi)反轉(zhuǎn),后續(xù)循環(huán)也再也碰不到節(jié)點(diǎn) 1 了,鏈表直接從 1 這里斷了。
到此這篇關(guān)于Python 多變量賦值問(wèn)題的文章就介紹到這了,更多相關(guān)Python 多變量賦值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python爬蟲(chóng)實(shí)戰(zhàn)之用selenium爬取某旅游網(wǎng)站
上一篇我們已經(jīng)知道怎么簡(jiǎn)單使用selenium了,那么我們就從這篇博客來(lái)動(dòng)手爬取網(wǎng)站吧,文中有非常詳細(xì)的代碼示例,需要的朋友可以參考下2021-06-06
Python利用AI接口實(shí)現(xiàn)摳圖并改圖片底色
時(shí)候我們的證件照需要換底色,又來(lái)不及去照相館拍照,用ps也不好摳圖,所以今天給你們分享一下如何用python來(lái)?yè)笀D,并換底色,需要的可以參考一下2022-09-09
anaconda如何創(chuàng)建和刪除環(huán)境
這篇文章主要介紹了anaconda如何創(chuàng)建和刪除環(huán)境,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
Python實(shí)現(xiàn)的多進(jìn)程和多線程功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)的多進(jìn)程和多線程功能,結(jié)合實(shí)例形式分析了Python多線程與多進(jìn)程實(shí)現(xiàn)分布式系統(tǒng)功能相關(guān)操作技巧,需要的朋友可以參考下2018-05-05
Python Web項(xiàng)目Cherrypy使用方法鏡像
這篇文章主要介紹了Python Web項(xiàng)目Cherrypy使用方法鏡像,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
關(guān)于Python核心框架tornado的異步協(xié)程的2種方法詳解
今天小編就為大家分享一篇關(guān)于Python核心框架tornado的異步協(xié)程的2種方法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-08-08
使用Pytorch訓(xùn)練分類問(wèn)題時(shí),分類準(zhǔn)確率的計(jì)算方式
這篇文章主要介紹了使用Pytorch訓(xùn)練分類問(wèn)題時(shí),分類準(zhǔn)確率的計(jì)算方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
如何使用Python在2秒內(nèi)評(píng)估國(guó)際象棋位置詳解
關(guān)心編程語(yǔ)言的使用趨勢(shì)的人都知道,最近幾年,國(guó)內(nèi)最火的兩種語(yǔ)言非Python與Go莫屬,下面這篇文章主要給大家介紹了關(guān)于如何使用Python在2秒內(nèi)評(píng)估國(guó)際象棋位置的相關(guān)資料,需要的朋友可以參考下2022-05-05

