成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Python 為什么能支持任意的真值判斷?

開(kāi)發(fā) 后端
Python 在涉及真值判斷(Truth Value Testing)時(shí),語(yǔ)法很簡(jiǎn)便。比如,在判斷某個(gè)對(duì)象是否不為 None 時(shí),或者判斷容器對(duì)象是否不為空時(shí),并不需要顯示地寫(xiě)出判斷條件,只需要在 if 或 while 關(guān)鍵字后面直接寫(xiě)上該對(duì)象即可。

Python 在涉及真值判斷(Truth Value Testing)時(shí),語(yǔ)法很簡(jiǎn)便。

[[336802]]

比如,在判斷某個(gè)對(duì)象是否不為 None 時(shí),或者判斷容器對(duì)象是否不為空時(shí),并不需要顯示地寫(xiě)出判斷條件,只需要在 if 或 while 關(guān)鍵字后面直接寫(xiě)上該對(duì)象即可。

下圖以列表為例,if my_list 這個(gè)簡(jiǎn)短的寫(xiě)法可以表達(dá)出兩層意思:

 

如果需要作出相反的判斷,即“如果為 None 或?yàn)榭?rdquo;,只需要寫(xiě)成if not my_list 即可。

與眾不同的真值判斷方式

通常而言,當(dāng)一個(gè)值本身是布爾類型時(shí),寫(xiě)成"if xxx"(如果真),在語(yǔ)義上就很好理解。如果 xxx 本身不是布爾類型時(shí),寫(xiě)成“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 這門(mén)動(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) 這種寫(xiě)法是多此一舉的了(我曾見(jiàn)到過(guò))。

至此,我們已經(jīng)回答了前文中提出的問(wèn)題。

驗(yàn)證真值判斷的過(guò)程

接下來(lái),有 3 個(gè)測(cè)試?yán)樱梢宰鬟M(jìn)一步的驗(yàn)證:

 

 

 

 

你可以暫停而思考下:bool(Test1) 與 bool(Test1()) 各是什么結(jié)果?然后依次判斷剩下的兩個(gè)類,結(jié)果又會(huì)是什么?

揭曉答案:

 

  1. bool(Test1)    # True 
  2. bool(Test2)    # True 
  3. bool(Test3)    # True 
  4.  
  5. bool(Test1())  # True 
  6. bool(Test2())  # False 
  7. 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ù)方法:

 

  1. hasattr(2020, "__bool__"
  2. 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)便的寫(xiě)法,雖然是正規(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

 

責(zé)任編輯:華軒 來(lái)源: Python貓
相關(guān)推薦

2021-03-03 08:01:58

Redis多線程程序

2020-07-22 08:01:41

Python開(kāi)發(fā)運(yùn)算符

2020-10-09 06:48:19

Pythonswitch語(yǔ)句

2020-07-22 18:11:07

神經(jīng)網(wǎng)絡(luò)函數(shù)代碼

2021-09-29 16:53:53

區(qū)塊鏈數(shù)據(jù)技術(shù)

2020-10-18 12:36:06

Python開(kāi)發(fā)函數(shù)

2021-02-01 13:53:53

StringlongJava

2016-10-21 16:24:55

IT支持SaaS云計(jì)算

2023-10-15 12:23:10

單線程Redis

2020-07-29 08:06:30

Kafka MQ消息

2021-09-26 05:04:45

瀏覽器AppActivity

2020-11-27 06:58:24

索引

2020-12-23 19:19:56

VR5G

2018-10-29 13:11:54

深度學(xué)習(xí)CNN提取圖像

2021-02-03 16:54:39

區(qū)塊鏈比特幣技術(shù)

2022-04-02 07:19:09

CORS前端安全

2021-08-02 09:31:20

Python工具代碼

2018-11-22 10:05:02

區(qū)塊鏈數(shù)字貨幣分叉

2021-04-27 18:12:22

WebSocket持久化連接HTTP

2021-10-27 07:15:36

Go 循環(huán)引用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产91久久久久蜜臀青青天草二 | 自拍视频在线观看 | 欧美精品在线播放 | 在线综合视频 | 欧美高清成人 | 四虎影音 | 在线一区| 香蕉视频黄色 | 福利社午夜影院 | 国产一区二区在线视频 | 国产成人精品久久二区二区91 | 国产高清av免费观看 | 国产免费一区二区三区最新6 | 成人精品一区二区三区中文字幕 | 免费看a | 成人综合视频在线观看 | 嫩草影院网址 | 欧美久久不卡 | 一区二区手机在线 | 日日精品 | 久久一区| 亚洲区视频 | 国产午夜三级一区二区三 | 久久国产精品无码网站 | 黄色片视频网站 | 久久国产精品-国产精品 | 亚洲精品一区二区网址 | 国产在线精品一区二区三区 | 亚洲综合三区 | av黄色片在线观看 | 精品av| 欧美福利 | 亚洲精品国产精品国自产在线 | 天堂一区二区三区 | 久久久亚洲一区 | 亚洲不卡视频 | 久久婷婷麻豆国产91天堂 | 久久精品国内 | 日韩精品一区二区三区四区视频 | 欧美一区二区三区久久精品视 | 日韩在线不卡 |