Python中怎么支持任意的真值判斷,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
10年積累的成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有呼蘭免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
Python 在涉及真值判斷(Truth Value Testing)時(shí),語(yǔ)法很簡(jiǎn)便。
比如,在判斷某個(gè)對(duì)象是否不為 None 時(shí),或者判斷容器對(duì)象是否不為空時(shí),并不需要顯示地寫出判斷條件,只需要在 if 或 while 關(guān)鍵字后面直接寫上該對(duì)象即可。
下圖以列表為例,if my_list 這個(gè)簡(jiǎn)短的寫法可以表達(dá)出兩層意思:
如果需要作出相反的判斷,即“如果為 None 或?yàn)榭铡保恍枰獙懗蒳f not my_list 即可。
與眾不同的真值判斷方式
通常而言,當(dāng)一個(gè)值本身是布爾類型時(shí),寫成"if xxx"(如果真),在語(yǔ)義上就很好理解。如果 xxx 本身不是布爾類型時(shí),寫成“if xxx”(如果某東西),則在語(yǔ)義上并不好理解。
在 C/C++/Java 之類的靜態(tài)語(yǔ)言中,通常要先基于 xxx 作一個(gè)比較操作,比如“if (xxx == null)”,以此得到一個(gè)布爾類型的值的結(jié)果,然后再進(jìn)行真值判斷。否則的話,若“if xxx”中有非布爾類型的值,則會(huì)報(bào)類型錯(cuò)誤。
Python 這門動(dòng)態(tài)語(yǔ)言在這種場(chǎng)景中表現(xiàn)出了一種靈活性,那么,我們的問(wèn)題來(lái)了:為什么 Python 不需要先做一次比較操作,直接就能對(duì)任意對(duì)象作真值判斷呢?
先來(lái)看看文檔 中對(duì)真值判斷的描述:
簡(jiǎn)單而言,Python 的任何對(duì)象都可以用在 if 或 while 或布爾操作(and、or、not)中,默認(rèn)情況下認(rèn)為它是 true,除非它有__bool__() 方法返回False 或者有__len__() 方法返回0 。
對(duì)于前面的例子,my_list 沒(méi)有__bool__() 方法,但是它有__len__() 方法,所以它是否為 true,取決于這個(gè)方法的返回值。
真值判斷的字節(jié)碼
接著,我們繼續(xù)刨根問(wèn)底:Python 為什么可以支持如此寬泛的真值判斷呢?在執(zhí)行if xxx 這樣的語(yǔ)句時(shí),它到底在做些什么?
對(duì)于第一個(gè)問(wèn)題,Python 有個(gè)內(nèi)置的 bool() 類型,可以將任意對(duì)象轉(zhuǎn)化成布爾值。那么,這是否意味著 Python 在進(jìn)行真值判斷時(shí),會(huì)隱式地 調(diào)用 bool() 呢(即轉(zhuǎn)化成if bool(xxx))?(答案為否,下文有分析)
對(duì)于第二個(gè)問(wèn)題,可以先用dis 模塊來(lái)查看下:
POP_JUMP_IF_FALSE指令對(duì)應(yīng)的是 if 語(yǔ)句那行,它的含義是:
If TOS is false, sets the bytecode counter to target. TOS is popped.
如果棧頂元素為 false,則跳轉(zhuǎn)到目標(biāo)位置。
這里只有跳轉(zhuǎn)動(dòng)作的描述,仍看不到一個(gè)普通對(duì)象是如何變成布爾對(duì)象的。
Python 在解釋器中到底是如何實(shí)現(xiàn)真值判斷的呢?
真值判斷的源碼實(shí)現(xiàn)
在微信群友 Jo 的幫助下,我找到了 CPython 的源碼(文件:ceval.c、object.c):
可以看出,對(duì)于布爾類型的對(duì)象(即 Py_True 和 Py_False),代碼會(huì)進(jìn)入到快速處理的分支;而對(duì)于其它對(duì)象,則會(huì)用 PyObject_IsTrue() 計(jì)算出一個(gè) int 類型的值。
PyObject_IsTrue() 函數(shù)在計(jì)算過(guò)程中,依次會(huì)獲取 nb_bool、mp_length 和 sq_length 的值,對(duì)應(yīng)的應(yīng)該就是 __bool__() 和 __len__() 這兩個(gè)魔術(shù)方法的返回值。
這個(gè)過(guò)程就是前文中所引用的官方文檔的描述,正是我們想要找的答案!
另外,對(duì)于內(nèi)置的 bool(),它的核心實(shí)現(xiàn)邏輯正是上面的 PyObject_IsTrue() 函數(shù),源碼如下(boolobject.c):
所以,Python 在對(duì)普通對(duì)象作真值判斷時(shí),并沒(méi)有隱式地調(diào)用 bool(),相反它調(diào)用了一個(gè)獨(dú)立的函數(shù)(PyObject_IsTrue()),而這個(gè)函數(shù)又被 bool() 所使用。
也就是說(shuō),bool() 與 if/while 語(yǔ)句對(duì)普通對(duì)象的真值判斷,事實(shí)上是基本相同的處理邏輯。 知道了原理,就會(huì)明白if bool(xxx) 這種寫法是多此一舉的了(我曾見(jiàn)到過(guò))。
至此,我們已經(jīng)回答了前文中提出的問(wèn)題。
驗(yàn)證真值判斷的過(guò)程
接下來(lái),有 3 個(gè)測(cè)試?yán)?,可以作進(jìn)一步的驗(yàn)證:
你可以暫停而思考下:bool(Test1) 與 bool(Test1()) 各是什么結(jié)果?然后依次判斷剩下的兩個(gè)類,結(jié)果又會(huì)是什么?
揭曉答案:
bool(Test1) # True bool(Test2) # True bool(Test3) # True bool(Test1()) # True bool(Test2()) # False bool(Test3()) # True
原因如下:
類對(duì)象沒(méi)被實(shí)例化時(shí),bool() 不會(huì)調(diào)用它的 __bool__() 或 __len__() 這兩個(gè)魔術(shù)方法
類對(duì)象被實(shí)例化后,若同時(shí)存在 __bool__() 或 __len__() 魔術(shù)方法,則 bool() 會(huì)先調(diào)用 __bool__() 方法(PS:這個(gè)方法要求返回值必須為 bool 類型,因此只要有它,就必然不需要再用__len__() 方法來(lái)判斷真假)
數(shù)字類型如何作真值判斷?
除了這 3 個(gè)例子,還有一種情況值得驗(yàn)證,那就是對(duì)于數(shù)字類型,它們是怎么做真值判斷的呢?
我們可以驗(yàn)證一下數(shù)字類型是否擁有那兩個(gè)魔術(shù)方法:
hasattr(2020, "__bool__") hasattr(2020, "__len__")
不難驗(yàn)證出,數(shù)字擁有的是 __bool__() 魔術(shù)方法,并沒(méi)有__len__() 魔術(shù)方法,而且所有類型的數(shù)字其實(shí)被分成了兩類:
__bool__() 返回 False:所有表示 0 的數(shù)字,例如0, 0.0, 0j, Decimal(0), Fraction(0, 1)
__bool__() 返回 True:所有其它非 0 的數(shù)字
文章小結(jié)
Python 中if xxx 這種簡(jiǎn)便的寫法,雖然是正規(guī)的真值判斷語(yǔ)法,并它但并不符合常規(guī)的語(yǔ)義。在 C/C++/Java 之類的語(yǔ)言中,要么 xxx 本身是布爾類型的值,要么是一種可返回布爾類型值的操作,但是在 Python 中,這個(gè)“xxx”竟然還可以是任意的 Python 對(duì)象!
本文通過(guò)對(duì)文檔、字節(jié)碼和 CPython 解釋器的源碼逐步分析,發(fā)現(xiàn)了 Python 的真值判斷過(guò)程并不簡(jiǎn)單,可以提煉出以下的幾個(gè)要點(diǎn):
if/while 是隱性的布爾操作符: 它們除了有“判斷”真假的作用,還具有隱式地將普通對(duì)象計(jì)算出布爾結(jié)果的功能。實(shí)際的操作是解釋器根據(jù)“POP_JUMP_IF_FALSE”指令來(lái)完成的,其核心邏輯跟內(nèi)置的 bool() 是共用了一個(gè)底層方法
真值判斷過(guò)程依賴兩個(gè)魔術(shù)方法: 除非被判斷對(duì)象有__bool__() 方法返回False 或者有__len__() 方法返回0 ,否則布爾操作的結(jié)果都是 True。兩個(gè)魔術(shù)方法總是會(huì)先計(jì)算__bool__()
數(shù)字類型也可做真值判斷: 數(shù)字有__bool__() 魔術(shù)方法,但沒(méi)有__len__() 魔術(shù)方法,除了表示 0 的數(shù)字為 False,其它數(shù)字都為 True
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。
新聞標(biāo)題:Python中怎么支持任意的真值判斷
地址分享:http://jinyejixie.com/article36/gpijpg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號(hào)、建站公司、網(wǎng)站改版、營(yíng)銷型網(wǎng)站建設(shè)、小程序開(kāi)發(fā)、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)