點(diǎn)評(píng):下面的程序?qū)?shí)際開(kāi)發(fā)并沒(méi)有什么意義,但卻是CPython中的一個(gè)大坑,這道題旨在考察面試者對(duì)官方的Python解釋器到底了解到什么程度。
a, b, c, d = 1, 1, 1000, 1000 print(a is b, c is d) def foo(): e = 1000 f = 1000 print(e is f, e is d) g = 1 print(g is a) foo()
結(jié)果: True False True False True
上面代碼中 a is b的結(jié)果是True但c is d的結(jié)果是False,這一點(diǎn)的確讓人費(fèi)解。這個(gè)結(jié)果是因?yàn)镃Python出于性能優(yōu)化的考慮,把頻繁使用的整數(shù)對(duì)象用一個(gè)叫small_ints的對(duì)象池緩存起來(lái)造成的。
small_ints緩存的整數(shù)值被設(shè)定為[-5, 256]這個(gè)區(qū)間,也就是說(shuō),如果使用CPython解釋器,在任何引用這些整數(shù)的地方,都不需要重新創(chuàng)建int對(duì)象,而是直接引用緩存池中的對(duì)象。
如果整數(shù)不在該范圍內(nèi),那么即便兩個(gè)整數(shù)的值相同,它們也是不同的對(duì)象。
CPython底層為了進(jìn)一步提升性能還做了一個(gè)設(shè)定:對(duì)于同一個(gè)代碼塊中值不在small_ints緩存范圍之內(nèi)的整數(shù),如果同一個(gè)代碼塊中已經(jīng)存在一個(gè)值與其相同的整數(shù)對(duì)象,那么就直接引用該對(duì)象,否則創(chuàng)建新的int對(duì)象。
需要大家注意的是,這條規(guī)則對(duì)數(shù)值型適用,但對(duì)字符串則需要考慮字符串的長(zhǎng)度,這一點(diǎn)可以自行證明。
擴(kuò)展:如果你用PyPy(另一種Python解釋器實(shí)現(xiàn),支持JIT,對(duì)CPython的缺點(diǎn)進(jìn)行了改良,在性能上優(yōu)于CPython,但對(duì)三方庫(kù)的支持略差)來(lái)運(yùn)行上面的代碼,你會(huì)發(fā)現(xiàn)所有的輸出都是True。