成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

淺談 (x, y) = (y, x)

AprilJ / 2127人閱讀

摘要:常用的模塊方法接收參數(shù)為一個代碼塊可以是模塊,類,方法,函數(shù),或者是對象,可以得到這個代碼塊對應(yīng)的字節(jié)碼指令序列。具體驗證可以分析下兩種方法的字節(jié)碼指令。

交換兩個變量的值,大家最常見的寫法是這樣的:

>>> temp = x
>>> x = y
>>> y = temp

但其實更 Pythonic 的寫法是這樣的:

>>> x, y = y, x

大家有沒有想過為什么在 Python 中可以這樣交換兩個變量的值?

Python 代碼是先解釋(這里的解釋是相對編譯而言的,Python 不同與 C/C++ 之類的編譯型語言,是需要從源文件編譯成機(jī)器指令)成 Python 字節(jié)碼(byte code, .pyc文件主要是用來存儲這些字節(jié)碼的)之后,再由 Python 解釋器來執(zhí)行這些字節(jié)碼的。一般來說,Python 語句會對應(yīng)若干字節(jié)碼指令,Python 的字節(jié)碼類似于匯編指令的中間語言,但是一個字節(jié)碼并不只是對應(yīng)一個機(jī)器指定。

內(nèi)置模塊 dis 可以用來分析字節(jié)碼。DOC

The dis module supports the analysis of CPython bytecode by disassembling it. The CPython bytecode which this module takes as an input is defined in the file Include/opcode.h and used by the compiler and the interpreter.

常用的 dis 模塊方法: dis.dis([bytesource])

dis.dis([bytesource])
Disassemble the bytesource object. bytesource can denote either a module, a class, a method, a function, or a code object. For a module, it disassembles all functions. For a class, it disassembles all methods. For a single code sequence, it prints one line per bytecode instruction. If no object is provided, it disassembles the last traceback.

dis.dis 接收參數(shù)為一個代碼塊(可以是模塊,類,方法,函數(shù),或者是對象),可以得到這個代碼塊對應(yīng)的字節(jié)碼指令序列。

>>> import dis
>>> def test():
...     a = 1
...     
... 
>>> dis.dis(test)
  3           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        

輸出的格式分別是:行號,地址,指令,操作參數(shù), 參數(shù)解釋(識別變量名稱,常量值等)

切入正題, 我們直接來看下第二種寫法的字節(jié)碼指令:

swap_2.py

x = 1
y = 3
x, y = y, x

python -m dis swap_2.py

  1           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (x)

  2           6 LOAD_CONST               1 (3)
              9 STORE_NAME               1 (y)

  3          12 LOAD_NAME                1 (y)
             15 LOAD_NAME                0 (x)
             18 ROT_TWO
             19 STORE_NAME               0 (x)
             22 STORE_NAME               1 (y)
             25 LOAD_CONST               2 (None)
             28 RETURN_VALUE

部分字節(jié)碼指令如下,具體的指令請移步官網(wǎng):

LOAD_CONST(consti)
Pushes co_consts[consti] onto the stack.
STORE_NAME(namei)
Implements name = TOS. namei is the index of name in the attribute co_names of the code object. The compiler tries to use STORE_FAST or STORE_GLOBAL if possible.
LOAD_NAME(namei)
Pushes the value associated with co_names[namei] onto the stack.
ROT_TWO()
Swaps the two top-most stack items.

解釋下上面的字節(jié)碼指令:

第一行執(zhí)行兩個字節(jié)碼指令, 分別是LOAD_CONSTSTORE_NAME,執(zhí)行的動作是將 co_consts[0] 壓棧(也就是常量表的第一個常量,整數(shù)1壓入棧中),然后獲取co_names[0]的變量名x(變量名表的第一個名字),棧頂元素(整數(shù)1)出棧和co_names[0]存儲到f->f_locals。

第二行的執(zhí)行方式如同第一行。

co_consts[0] = 1
co_names[0] = x
f->f_locals["x"] = 1

co_consts[1] = 3
co_names[1] = y
f->f_locals["y"] = 3

重點(diǎn)在第三行,前兩行的計算順序都是從友往左進(jìn)行的(一般情況下, Python 表達(dá)式的計算順序是從左到右,但是在表達(dá)式賦值的時候,表達(dá)式右邊的操作數(shù)優(yōu)先于左邊),也就是說,第四行是這樣執(zhí)行的,先創(chuàng)建元組(y, x),執(zhí)行的動作是兩個 LOAD_NAME,會依次搜索local,global,builtin名字空間中的co_names[1](對應(yīng)變量名y)和co_names[0](對應(yīng)變量名x)并把相對應(yīng)的值壓棧。接下去執(zhí)行的動作是交換ROT_TWO, 交換棧頂?shù)膬蓚€元素位置。

從下一個執(zhí)行指令就可以看出來,先獲取co_names[0]的變量名x,棧頂元素(現(xiàn)在是原先y的值)出棧并儲存,兩次存儲就實現(xiàn)了交換兩個變量的值。

第二種方法不借助任何中間變量并且能夠獲得更好的性能。我們可以簡單測試下:

>>> from timeit import Timer
>>> Timer("temp = x;x = y;y = temp", "x=2;y=3").timeit()
0.030814170837402344
>>> Timer("x, y = y, x", "x=2;y=3").timeit()
0.027340173721313477

為什么第二種方法消耗的時間更少呢?可以猜測一下,是中間變量賦值引起的耗時。具體驗證可以分析下兩種方法的字節(jié)碼指令。

Life such short,be Pythonic .

Blog : JunNplus

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/37631.html

相關(guān)文章

  • 淺談js中的閉包

    摘要:對于一個個剛剛接觸前端的新手,天天聽人講閉包,聽的那個高大尚,心中對各位技術(shù)大佬是那個的膜拜,于是做為前端菜鳥的我,就去了解了傳說中的閉包。 對于一個個剛剛接觸前端的新手,天天聽人講閉包,聽的那個高大尚,心中對各位技術(shù)大佬是那個的膜拜,于是做為前端菜鳥的我,就去了解了傳說中的閉包。 何為閉包?通俗易懂的講,就是可以調(diào)用函數(shù)內(nèi)部的變量和方法 舉例說明如下: function t...

    kumfo 評論0 收藏0
  • Python之淺談exec()函數(shù)

    摘要:本次分享講簡單聊聊函數(shù)的用法,希望能給讀者一點(diǎn)啟示和參考。在最后的語句中,我們給出了的值,并且值重復(fù),函數(shù)接收后面一個值,且值傳遞不起作用,因此輸出結(jié)果為本次分享到此結(jié)束。本文介紹了幾個函數(shù)使用的例子,希望能拋磚引玉,也歡迎大家多多交流 ??在Python中,exec()是一個十分有趣且實用的內(nèi)置函數(shù),不同于eval()函數(shù)只能執(zhí)行計算數(shù)學(xué)表達(dá)式的結(jié)果的功能,exec()能夠動態(tài)地執(zhí)行...

    hedzr 評論0 收藏0
  • 淺談深拷貝和淺拷貝

    摘要:而引用類型值是指那些保存堆內(nèi)存中的對象,意思是變量中保存的實際上只是一個指針,這個指針指向內(nèi)存中的另一個位置,該位置保存對象。而堆內(nèi)存主要負(fù)責(zé)對象這種變量類型的存儲。我們需要明確一點(diǎn),深拷貝與淺拷貝的概念只存在于引用類型。 深拷貝和淺拷貝 說起深拷貝和淺拷貝,首先我們來看兩個栗子 // 栗子1 var a = 1,b=a; console.log(a); console.log(b) ...

    littleGrow 評論0 收藏0
  • 淺談 python 中的 sorted()與sort()

    摘要:返回值是一個經(jīng)過排序的可迭代類型,與一樣。注一般來說,和可以使用表達(dá)式。與的不同在于,是在原位重新排列列表,而是產(chǎn)生一個新的列表。 我們需要對List進(jìn)行排序,Python提供了兩個方法 對給定的List L進(jìn)行排序,方法1.用List的成員函數(shù)sort進(jìn)行排序方法2.用built-in函數(shù)sorted進(jìn)行排序(從2.4開始) ----------------------------...

    lansheng228 評論0 收藏0
  • 由 sort 中 key 的用法淺談 python

    摘要:但是實際寫程序中,我們經(jīng)常會寫出許多繁雜的丑陋的代碼。特別推薦,許多代碼讓我獲益匪淺,比如這里對的使用。用可以寫出很簡單直觀的代碼,如下當(dāng)然,上面不考慮效率,這里有一個利用分治法思想的高效的方法。更多文章更多閱讀中參數(shù)的用法高級編程技巧 用 Python 時間也算不短了,但總感覺自己在用寫 C++ 代碼的思維寫 Python,沒有真正用到其作為腳本語言的優(yōu)勢。之前刷 LeetCode ...

    keke 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<