<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python 為什么只需一條語句“a,b=b,a”,就能直接交換兩個變量?

          共 2688字,需瀏覽 6分鐘

           ·

          2022-05-16 08:12

          點擊上方小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時間送達(dá)

          從接觸 Python 時起,我就覺得 Python 的元組解包(unpacking)挺有意思,非常簡潔好用。

          最顯而易見的例子就是多重賦值,即在一條語句中同時給多個變量賦值:

          >>>?x,?y?=?1,?2
          >>>?print(x,?y)??#?結(jié)果:1 2

          在此例中,賦值操作符“=”號的右側(cè)的兩個數(shù)字會被存入到一個元組中,即變成 (1,2),然后再被解包,依次賦值給“=”號左側(cè)的兩個變量。

          如果我們直接寫x = 1,2 ,然后打印出 x,或者在“=”號右側(cè)寫成一個元組,就能證實到這一點:

          >>>?x?=?1,?2
          >>>?print(x)?????#?結(jié)果:(1, 2)
          >>>?x,?y?=?(1,?2)
          >>>?print(x,?y)??#?結(jié)果:1 2

          一些博客或公眾號文章在介紹到這個特性時,通常會順著舉一個例子,即基于兩個變量,直接交換它們的值:

          >>>?x,?y?=?1,?2
          >>>?x,?y?=?y,?x
          >>>?print(x,?y)?#?結(jié)果:2 1

          一般而言,交換兩個變量的操作需要引入第三個變量。道理很簡單,如果要交換兩個杯子中所裝的水,自然會需要第三個容器作為中轉(zhuǎn)。

          然而,Python 的寫法并不需要借助中間變量,它的形式就跟前面的解包賦值一樣。正因為這個形式相似,很多人就誤以為 Python 的變量交換操作也是基于解包操作。

          但是,事實是否如此呢?

          我搜索了一番,發(fā)現(xiàn)有人試圖回答過這個問題,但是他們的回答基本不夠全面。(當(dāng)然,有不少是錯誤的答案,還有更多人只是知其然,卻從未想過要知其所以然)

          先把本文的答案放出來吧:Python 的交換變量操作不完全基于解包操作,有時候是,有時候不是!

          有沒有覺得這個答案很神奇呢?是不是聞所未聞?!

          到底怎么回事呢?先來看看標(biāo)題中最簡單的兩個變量的情況,我們上dis 大殺器看看編譯的字節(jié)碼:

          上圖開了兩個窗口,可以方便比較“a,b=b,a”與“a,b=1,2”的不同:
          • “a,b=b,a”操作:兩個 LOAD_FAST 是從局部作用域中讀取變量的引用,并存入棧中,接著是最關(guān)鍵的 ROT_TWO 操作,它會交換兩個變量的引用值,然后兩個 STORE_FAST 是將棧中的變量寫入局部作用域中。

          • “a,b=1,2”操作:第一步 LOAD_CONST 把“=”號右側(cè)的兩個數(shù)字作為元組放到棧中,第二步 UNPACK_SEQUENCE 是序列解包,接著把解包結(jié)果寫入局部作用域的變量上。

          很明顯,形式相似的兩種寫法實際上完成的操作并不相同。在交換變量的操作中,并沒有裝包和解包的步驟!

          ROT_TWO 指令是 CPython 解釋器實現(xiàn)的對于棧頂兩個元素的快捷操作,改變它們指向的引用對象。

          還有兩個類似的指令是 ROT_THREE 和 ROT_FOUR,分別是快捷交換三和四個變量(摘自:ceval.c 文件,最新的 3.9 分支):

          預(yù)定義的棧頂操作如下:

          查看官方文檔中對于這幾個指令的解釋,其中 ROT_FOUR 是 3.8 版本新加的:

          ROT_TWO

          Swaps the two top-most stack items.


          ROT_THREE

          Lifts second and third stack item one position up, moves top down to position three.


          ROT_FOUR

          Lifts second, third and forth stack items one position up, moves top down to position four.
          New in version 3.8.

          CPython 應(yīng)該是以為這幾種變量的交換操作很常見,因此才提供了專門的優(yōu)化指令。就像 [-5,256] 這些小整數(shù)被預(yù)先放到了整數(shù)池里一樣。

          對于更多變量的交換操作,實際上則會用到前面說的解包操作:

          截圖中的 BUILD_TUPLE 指令會將給定數(shù)量的棧頂元素創(chuàng)建成元組,然后被 UNPACK_SEQUENCE 指令解包,再依次賦值。

          值得一提的是,此處之所以比前面的“a,b=1,2”多出一個 build 操作,是因為每個變量的 LOAD_FAST 需要先單獨入棧,無法直接被組合成 LOAD_CONST 入棧。也就是說,“=”號右側(cè)有變量時,不會出現(xiàn)前文中的 ?LOAD_CONST 一個元組的情況。

          最后還有一個值得一提的細(xì)節(jié),那幾個指令是跟棧中元素的數(shù)量有關(guān),而不是跟賦值語句中實際交換的變量數(shù)有關(guān)??匆粋€例子就明白了:

          分析至此,你應(yīng)該明白前文中的結(jié)論是怎么回事了吧?

          我們稍微總結(jié)一下:
          • Python 能在一條語句中實現(xiàn)多重賦值,這是利用了序列解包的特性

          • Python 能在一條語句中實現(xiàn)變量交換,不需引入中間變量,在變量數(shù)少于 4 個時(3.8 版本起是少于 5 個),CPython 是利用了 ROT_* 指令來交換棧中的元素,當(dāng)變量數(shù)超出時,則是利用了序列解包的特性。

          • 序列解包是 Python 的一大特性,但是在本文的例子中,CPython 解釋器在小小的操作中還提供了幾個優(yōu)化的指令,這絕對會超出大多數(shù)人的認(rèn)知

          下載1:OpenCV-Contrib擴展模塊中文版教程
          在「小白學(xué)視覺」公眾號后臺回復(fù):擴展模塊中文教程即可下載全網(wǎng)第一份OpenCV擴展模塊教程中文版,涵蓋擴展模塊安裝、SFM算法、立體視覺、目標(biāo)跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺實戰(zhàn)項目52講
          小白學(xué)視覺公眾號后臺回復(fù):Python視覺實戰(zhàn)項目,即可下載包括圖像分割、口罩檢測、車道線檢測、車輛計數(shù)、添加眼線、車牌識別、字符識別、情緒檢測、文本內(nèi)容提取、面部識別等31個視覺實戰(zhàn)項目,助力快速學(xué)校計算機視覺。

          下載3:OpenCV實戰(zhàn)項目20講
          小白學(xué)視覺公眾號后臺回復(fù):OpenCV實戰(zhàn)項目20講,即可下載含有20個基于OpenCV實現(xiàn)20個實戰(zhàn)項目,實現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。

          交流群


          歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN、算法競賽等微信群(以后會逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進(jìn)入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~


          瀏覽 24
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  男女生操逼 | 久久久成人视频 | 在线波多野结衣 | 成人免费精品视频 | 国产AV激情 |