Python解惑之整數(shù)比較詳解
前言
在 Python 中一切都是對(duì)象,毫無例外整數(shù)也是對(duì)象,對(duì)象之間比較是否相等可以用==,也可以用is。
==和is操作的區(qū)別是:
- is比較的是兩個(gè)對(duì)象的id值是否相等,也就是比較倆對(duì)象是否為同一個(gè)實(shí)例對(duì)象,是否指向同一個(gè)內(nèi)存地址。
- ==比較的是兩個(gè)對(duì)象的內(nèi)容是否相等,默認(rèn)會(huì)調(diào)用對(duì)象的
__eq__()
方法。
清楚is和==的區(qū)別之后,對(duì)此也許你有可能會(huì)遇到下面的這些困惑,于是就有了這樣一篇文章,試圖把Python中一些隱晦的東西趴出來,希望對(duì)你有一定的幫助。
我們先來看兩段代碼:
片段一:
>>> a = 256 >>> b = 256 >>> a == b True >>>
片段二:
>>> a = 256 >>> b = 256 >>> a is b True >>>
在交互式命令行執(zhí)行上面兩段代碼,代碼片段一中的a==b返回True很好理解,因?yàn)閮蓚€(gè)對(duì)象的值都是256,對(duì)于片段二,a is b也返回True,這說明a和b是指向同一個(gè)對(duì)象的,可以檢查一下他們的id值是否相等:
>>> id(a) 8213296 >>> id(b) 8213296 >>>
結(jié)果證明他倆的確是同一個(gè)對(duì)象,指向的是同一個(gè)內(nèi)存地址。那是不是所有的整數(shù)對(duì)象只要兩個(gè)對(duì)象的值(內(nèi)容)相等,它們就是同一個(gè)實(shí)例對(duì)象呢?換句話說,對(duì)于整數(shù)對(duì)象只要==返回True,is操作也會(huì)返回True嗎?
帶著這個(gè)問題來看下面這兩段代碼:
片段一:
>>> a = 257 >>> b = 257 >>> a == b True >>>
片段二:
>>> a = 257 >>> b = 257 >>> a is b False >>>
對(duì)于257,a is b返回的竟然是False,結(jié)果可能在你的意料之中,也有可能出乎你的意料,但不管怎么,我們還是要刨根問底,找出問題的真相。
解惑一
出于對(duì)性能的考慮,Python內(nèi)部做了很多的優(yōu)化工作,對(duì)于整數(shù)對(duì)象,Python把一些頻繁使用的整數(shù)對(duì)象緩存起來,保存到一個(gè)叫small_ints的鏈表中,在Python的整個(gè)生命周期內(nèi),任何需要引用這些整數(shù)對(duì)象的地方,都不再重新創(chuàng)建新的對(duì)象,而是直接引用緩存中的對(duì)象。Python把這些可能頻繁使用的整數(shù)對(duì)象規(guī)定在范圍[-5, 256]之間的小對(duì)象放在small_ints中,但凡是需要用些小整數(shù)時(shí),就從這里面取,不再去臨時(shí)創(chuàng)建新的對(duì)象。因?yàn)?57不再小整數(shù)范圍內(nèi),因此盡管a和b的值是一樣,但是他們?cè)赑ython內(nèi)部卻是以兩個(gè)獨(dú)立的對(duì)象存在的,各自為政,互不干涉。
弄明白第一個(gè)問題后,我們繼續(xù)在Python交互式命令行中寫一個(gè)函數(shù),再來看下面這段代碼:
片段一:
>>> c = 257 >>> def foo(): ... a = 257 ... b = 257 ... print a is b ... print a is c ... >>> foo() True False
呃,什么情況,是的,你沒看錯(cuò),片段一中的這段代碼 a、b 值都是257的情況下,出現(xiàn)了a is b返回True,而a is c 返回的False,a、b、c的值都為257,為什么會(huì)出現(xiàn)不同的結(jié)果呢?這對(duì)于剛剛好不容易建立起來的認(rèn)知就被徹底否決了嗎,那這段代碼中究竟發(fā)生了什么?難道解惑一中的結(jié)論是錯(cuò)誤的嗎?
解惑二
A Python program is constructed from code blocks. A block is a piece of Python program text that is executed as a unit. The following are blocks: a module, a function body, and a class definition. Each command typed interactively is a block. A script file (a file given as standard input to the interpreter or specified as a command line argument to the interpreter) is a code block. A script command (a command specified on the interpreter command line with the ‘-c‘ option) is a code block. structure-of-a-program
為了弄清楚這個(gè)問題,我們有必要先理解程序代碼塊的概念。Python程序由代碼塊構(gòu)成,代碼塊作為程序的一個(gè)最小基本單位來執(zhí)行。一個(gè)模塊文件、一個(gè)函數(shù)體、一個(gè)類、交互式命令中的單行代碼都叫做一個(gè)代碼塊。在上面這段代碼中,由兩個(gè)代碼塊構(gòu)成,c = 257作為一個(gè)代碼塊,函數(shù)foo作為另外一個(gè)代碼塊。Python內(nèi)部為了將性能進(jìn)一步的提高,凡是在一個(gè)代碼塊中創(chuàng)建的整數(shù)對(duì)象,如果存在一個(gè)值與其相同的對(duì)象于該代碼塊中了,那么就直接引用,否則創(chuàng)建一個(gè)新的對(duì)象出來。Python出于對(duì)性能的考慮,但凡是不可變對(duì)象,在同一個(gè)代碼塊中的對(duì)象,只有是值相同的對(duì)象,就不會(huì)重復(fù)創(chuàng)建,而是直接引用已經(jīng)存在的對(duì)象。因此,不僅是整數(shù)對(duì)象,還有字符串對(duì)象也遵循同樣的原則。所以 a is b就理所當(dāng)然的返回True了,而c和a不在同一個(gè)代碼塊中,因此在Python內(nèi)部創(chuàng)建了兩個(gè)值都是257的對(duì)象。為了驗(yàn)證剛剛的結(jié)論,我們可以借用dis模塊從字節(jié)碼的角度來看看這段代碼。
>>> import dis >>> dis.dis(foo) 2 0 LOAD_CONST 1 (257) 3 STORE_FAST 0 (a) 3 6 LOAD_CONST 1 (257) 9 STORE_FAST 1 (b) 4 12 LOAD_FAST 0 (a) 15 LOAD_FAST 1 (b) 18 COMPARE_OP 8 (is) 21 PRINT_ITEM 22 PRINT_NEWLINE 5 23 LOAD_FAST 0 (a) 26 LOAD_GLOBAL 0 (c) 29 COMPARE_OP 8 (is) 32 PRINT_ITEM 33 PRINT_NEWLINE 34 LOAD_CONST 0 (None) 37 RETURN_VALUE
可以看出兩個(gè)257都是從常量池的同一個(gè)位置co_consts[1]獲取的。
總結(jié)
一番長(zhǎng)篇大論之后,得出兩點(diǎn)結(jié)論:
1、小整數(shù)對(duì)象[-5,256]是全局解釋器范圍內(nèi)被重復(fù)使用,永遠(yuǎn)不會(huì)被GC回收。
2、同一個(gè)代碼塊中的不可變對(duì)象,只要值是相等的就不會(huì)重復(fù)創(chuàng)建新的對(duì)象。似乎這些知識(shí)點(diǎn)對(duì)日常的工作一點(diǎn)忙也幫不上,因?yàn)槟愀静粫?huì)用is來比較兩個(gè)整數(shù)對(duì)象的值是否相等。那為什么還要拿出來討論呢?嗯,程序員學(xué)知識(shí),不應(yīng)該淺嘗輒止,要充分發(fā)揮死磕到底的精神。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者使用python能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Pygame鼠標(biāo)進(jìn)行圖片的移動(dòng)與縮放案例詳解
pygame是Python的第三方庫(kù),里面提供了使用Python開發(fā)游戲的基礎(chǔ)包。本文將介紹如何通過Pygame實(shí)現(xiàn)鼠標(biāo)進(jìn)行圖片的移動(dòng)與縮放,感興趣的可以關(guān)注一下2021-12-12Python函數(shù)參數(shù)類型及排序原理總結(jié)
這篇文章主要介紹了Python函數(shù)參數(shù)類型及排序原理總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12python安裝包出現(xiàn)Retrying?(Retry(total=4,?connect=None,?read=No
這篇文章主要給大家介紹了關(guān)于python安裝包出現(xiàn)Retrying?(Retry(total=4,?connect=None,?read=None,?redirect=None,?status=None))問題的解決方法,需要的朋友可以參考下2022-09-09使用python來調(diào)用CAN通訊的DLL實(shí)現(xiàn)方法
今天小編就為大家分享一篇使用python來調(diào)用CAN通訊的DLL實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07封裝?Python?時(shí)間處理庫(kù)創(chuàng)建自己的TimeUtil類示例
這篇文章主要為大家介紹了封裝?Python?時(shí)間處理庫(kù)創(chuàng)建自己的TimeUtil類示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2023-05-05Python制作一個(gè)隨機(jī)抽獎(jiǎng)小工具的實(shí)現(xiàn)
最近在工作中面向社群玩家組織了一場(chǎng)活動(dòng),需要進(jìn)行隨機(jī)抽獎(jiǎng),就做了一個(gè)簡(jiǎn)單的隨機(jī)抽獎(jiǎng)小工具。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07淺談Python數(shù)據(jù)類型之間的轉(zhuǎn)換
下面小編就為大家?guī)硪黄獪\談Python數(shù)據(jù)類型之間的轉(zhuǎn)換。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06python?Seaborn繪制統(tǒng)計(jì)圖全面指南(直方圖散點(diǎn)圖小提琴圖熱力圖相關(guān)系數(shù)圖多張合并)
這篇文章主要介紹了python?Seaborn繪制統(tǒng)計(jì)圖全面指南,包括直方圖,散點(diǎn)圖,小提琴圖,熱力圖,相關(guān)系數(shù)圖及多張圖合并的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助2024-01-01