欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

如何理解Python的二元算術(shù)運(yùn)算

本篇內(nèi)容介紹了“如何理解Python的二元算術(shù)運(yùn)算”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)始終堅(jiān)持【策劃先行,效果至上】的經(jīng)營(yíng)理念,通過(guò)多達(dá)10多年累計(jì)超上千家客戶(hù)的網(wǎng)站建設(shè)總結(jié)了一套系統(tǒng)有效的推廣解決方案,現(xiàn)已廣泛運(yùn)用于各行各業(yè)的客戶(hù),其中包括:陽(yáng)臺(tái)護(hù)欄等企業(yè),備受客戶(hù)稱(chēng)譽(yù)。

查看 C 代碼

按照慣例,我們從查看 CPython 解釋器編譯的字節(jié)碼開(kāi)始。

>>> def sub(): a - b ...  >>> import dis >>> dis.dis(sub)   1           0 LOAD_GLOBAL              0 (a)               2 LOAD_GLOBAL              1 (b)               4 BINARY_SUBTRACT               6 POP_TOP               8 LOAD_CONST               0 (None)              10 RETURN_VALUE

看起來(lái)我們需要深入研究 BINARY_SUBTRACT 操作碼。翻查 Python/ceval.c 文件,可以看到實(shí)現(xiàn)該操作碼的 C 代碼如下:

case TARGET(BINARY_SUBTRACT): {     PyObject *right = POP();     PyObject *left = TOP();     PyObject *diff = PyNumber_Subtract(left, right);     Py_DECREF(right);     Py_DECREF(left);     SET_TOP(diff);     if (diff == NULL)     goto error;     DISPATCH(); }

來(lái)源:https://github.com/python/cpython/blob/6f8c8320e9eac9bc7a7f653b43506e75916ce8e8/Python/ceval.c#L1569-L1579

這里的關(guān)鍵代碼是PyNumber_Subtract(),實(shí)現(xiàn)了減法的實(shí)際語(yǔ)義。繼續(xù)查看該函數(shù)的一些宏,可以找到binary_op1()  函數(shù)。它提供了一種管理二元操作的通用方法。

不過(guò),我們不把它作為實(shí)現(xiàn)的參考,而是要用Python的數(shù)據(jù)模型,官方文檔很好,清楚介紹了減法所使用的語(yǔ)義。

從數(shù)據(jù)模型中學(xué)習(xí)

通讀數(shù)據(jù)模型的文檔,你會(huì)發(fā)現(xiàn)在實(shí)現(xiàn)減法時(shí),有兩個(gè)方法起到了關(guān)鍵作用:__sub__ 和 __rsub__。

1、__sub__()方法

當(dāng)執(zhí)行a - b 時(shí),會(huì)在 a 的類(lèi)型中查找__sub__(),然后把 b 作為它的參數(shù)。這很像我寫(xiě)屬性訪問(wèn)的文章  里的__getattribute__(),特殊/魔術(shù)方法是根據(jù)對(duì)象的類(lèi)型來(lái)解析的,并不是出于性能目的而解析對(duì)象本身;在下面的示例代碼中,我使用_mro_getattr()  表示此過(guò)程。

因此,如果已定義 __sub__(),則 type(a).__sub__(a,b)  會(huì)被用來(lái)作減法操作。(譯注:魔術(shù)方法屬于對(duì)象的類(lèi)型,不屬于對(duì)象)

這意味著在本質(zhì)上,減法只是一個(gè)方法調(diào)用!你也可以將它理解成標(biāo)準(zhǔn)庫(kù)中的 operator.sub() 函數(shù)。

我們將仿造該函數(shù)實(shí)現(xiàn)自己的模型,用 lhs 和 rhs 兩個(gè)名稱(chēng),分別表示 a-b 的左側(cè)和右側(cè),以使示例代碼更易于理解。

# 通過(guò)調(diào)用__sub__()實(shí)現(xiàn)減法  def sub(lhs: Any, rhs: Any, /) -> Any:     """Implement the binary operation `a - b`."""     lhs_type = type(lhs)     try:         subtract = _mro_getattr(lhs_type, "__sub__")     except AttributeError:         msg = f"unsupported operand type(s) for -: {lhs_type!r} and {type(rhs)!r}"         raise TypeError(msg)     else:         return subtract(lhs, rhs)

2、讓右側(cè)使用__rsub__()

但是,如果 a 沒(méi)有實(shí)現(xiàn)__sub__() 怎么辦?如果 a 和 b 是不同的類(lèi)型,那么我們會(huì)嘗試調(diào)用 b 的 __rsub__()(__rsub__  里面的“r”表示“右”,代表在操作符的右側(cè))。

當(dāng)操作的雙方是不同類(lèi)型時(shí),這樣可以確保它們都有機(jī)會(huì)嘗試使表達(dá)式生效。當(dāng)它們相同時(shí),我們假設(shè)__sub__()  就能夠處理好。但是,即使兩邊的實(shí)現(xiàn)相同,你仍然要調(diào)用__rsub__(),以防其中一個(gè)對(duì)象是其它的(子)類(lèi)。

3、不關(guān)心類(lèi)型

現(xiàn)在,表達(dá)式雙方都可以參與運(yùn)算!但是,如果由于某種原因,某個(gè)對(duì)象的類(lèi)型不支持減法怎么辦(例如不支持 4 - “stuff”)?在這種情況下,__sub__  或__rsub__ 能做的就是返回 NotImplemented。

這是給 Python  返回的信號(hào),它應(yīng)該繼續(xù)執(zhí)行下一個(gè)操作,嘗試使代碼正常運(yùn)行。對(duì)于我們的代碼,這意味著需要先檢查方法的返回值,然后才能假定它起作用。

# 減法的實(shí)現(xiàn),其中表達(dá)式的左側(cè)和右側(cè)均可參與運(yùn)算 _MISSING = object()  def sub(lhs: Any, rhs: Any, /) -> Any:         # lhs.__sub__         lhs_type = type(lhs)         try:             lhs_method = debuiltins._mro_getattr(lhs_type, "__sub__")         except AttributeError:             lhs_method = _MISSING          # lhs.__rsub__ (for knowing if rhs.__rub__ should be called first)         try:             lhs_rmethod = debuiltins._mro_getattr(lhs_type, "__rsub__")         except AttributeError:             lhs_rmethod = _MISSING          # rhs.__rsub__         rhs_type = type(rhs)         try:             rhs_method = debuiltins._mro_getattr(rhs_type, "__rsub__")         except AttributeError:             rhs_method = _MISSING          call_lhs = lhs, lhs_method, rhs         call_rhs = rhs, rhs_method, lhs          if lhs_type is not rhs_type:             calls = call_lhs, call_rhs         else:             calls = (call_lhs,)          for first_obj, meth, second_obj in calls:             if meth is _MISSING:                 continue             value = meth(first_obj, second_obj)             if value is not NotImplemented:                 return value         else:             raise TypeError(                 f"unsupported operand type(s) for -: {lhs_type!r} and {rhs_type!r}"             )

4、子類(lèi)優(yōu)先于父類(lèi)

如果你看一下__rsub__()  的文檔,就會(huì)注意到一條注釋。它說(shuō)如果一個(gè)減法表達(dá)式的右側(cè)是左側(cè)的子類(lèi)(真正的子類(lèi),同一類(lèi)的不算),并且兩個(gè)對(duì)象的__rsub__()  方法不同,則在調(diào)用__sub__() 之前會(huì)先調(diào)用__rsub__()。換句話(huà)說(shuō),如果 b 是 a 的子類(lèi),調(diào)用的順序就會(huì)被顛倒。

這似乎是一個(gè)很奇怪的特例,但它背后是有原因的。當(dāng)你創(chuàng)建一個(gè)子類(lèi)時(shí),這意味著你要在父類(lèi)提供的操作上注入新的邏輯。這種邏輯不一定要加給父類(lèi),否則父類(lèi)在對(duì)子類(lèi)操作時(shí),就很容易覆蓋子類(lèi)想要實(shí)現(xiàn)的操作。

具體來(lái)說(shuō),假設(shè)有一個(gè)名為 Spam 的類(lèi),當(dāng)你執(zhí)行 Spam() - Spam() 時(shí),得到一個(gè) LessSpam 的實(shí)例。接著你又創(chuàng)建了一個(gè) Spam  的子類(lèi)名為 Bacon,這樣,當(dāng)你用 Spam 去減 Bacon 時(shí),你得到的是 VeggieSpam。

如果沒(méi)有上述規(guī)則,Spam() - Bacon() 將得到 LessSpam,因?yàn)?Spam 不知道減掉 Bacon 應(yīng)該得出  VeggieSpam。

但是,有了上述規(guī)則,就會(huì)得到預(yù)期的結(jié)果 VeggieSpam,因?yàn)?Bacon.__rsub__() 首先會(huì)在表達(dá)式中被調(diào)用(如果計(jì)算的是 Bacon()  - Spam(),那么也會(huì)得到正確的結(jié)果,因?yàn)槭紫葧?huì)調(diào)用 Bacon.__sub__(),因此,規(guī)則里才會(huì)說(shuō)兩個(gè)類(lèi)的不同的方法需有區(qū)別,而不僅僅是一個(gè)由  issubclass() 判斷出的子類(lèi)。)

# Python中減法的完整實(shí)現(xiàn) _MISSING = object()  def sub(lhs: Any, rhs: Any, /) -> Any:         # lhs.__sub__         lhs_type = type(lhs)         try:             lhs_method = debuiltins._mro_getattr(lhs_type, "__sub__")         except AttributeError:             lhs_method = _MISSING          # lhs.__rsub__ (for knowing if rhs.__rub__ should be called first)         try:             lhs_rmethod = debuiltins._mro_getattr(lhs_type, "__rsub__")         except AttributeError:             lhs_rmethod = _MISSING          # rhs.__rsub__         rhs_type = type(rhs)         try:             rhs_method = debuiltins._mro_getattr(rhs_type, "__rsub__")         except AttributeError:             rhs_method = _MISSING          call_lhs = lhs, lhs_method, rhs         call_rhs = rhs, rhs_method, lhs          if (             rhs_type is not _MISSING  # Do we care?             and rhs_type is not lhs_type  # Could RHS be a subclass?             and issubclass(rhs_type, lhs_type)  # RHS is a subclass!             and lhs_rmethod is not rhs_method  # Is __r*__ actually different?         ):             calls = call_rhs, call_lhs         elif lhs_type is not rhs_type:             calls = call_lhs, call_rhs         else:             calls = (call_lhs,)          for first_obj, meth, second_obj in calls:             if meth is _MISSING:                 continue             value = meth(first_obj, second_obj)             if value is not NotImplemented:                 return value         else:             raise TypeError(                 f"unsupported operand type(s) for -: {lhs_type!r} and {rhs_type!r}"             )

推廣到其它二元運(yùn)算

解決掉了減法運(yùn)算,那么其它二元運(yùn)算又如何呢?好吧,事實(shí)證明它們的操作相同,只是碰巧使用了不同的特殊/魔術(shù)方法名稱(chēng)。

所以,如果我們可以推廣這種方法,那么我們就可以實(shí)現(xiàn) 13 種操作的語(yǔ)義:+  、-、*、@、/、//、%、**、<<、>>、&、^、和 |。

由于閉包和 Python 在對(duì)象自省上的靈活性,我們可以提煉出 operator 函數(shù)的創(chuàng)建。

# 一個(gè)創(chuàng)建閉包的函數(shù),實(shí)現(xiàn)了二元運(yùn)算的邏輯 _MISSING = object()   def _create_binary_op(name: str, operator: str) -> Any:     """Create a binary operation function.      The `name` parameter specifies the name of the special method used for the     binary operation (e.g. `sub` for `__sub__`). The `operator` name is the     token representing the binary operation (e.g. `-` for subtraction).      """      lhs_method_name = f"__{name}__"      def binary_op(lhs: Any, rhs: Any, /) -> Any:         """A closure implementing a binary operation in Python."""         rhs_method_name = f"__r{name}__"          # lhs.__*__         lhs_type = type(lhs)         try:             lhs_method = debuiltins._mro_getattr(lhs_type, lhs_method_name)         except AttributeError:             lhs_method = _MISSING          # lhs.__r*__ (for knowing if rhs.__r*__ should be called first)         try:             lhs_rmethod = debuiltins._mro_getattr(lhs_type, rhs_method_name)         except AttributeError:             lhs_rmethod = _MISSING          # rhs.__r*__         rhs_type = type(rhs)         try:             rhs_method = debuiltins._mro_getattr(rhs_type, rhs_method_name)         except AttributeError:             rhs_method = _MISSING          call_lhs = lhs, lhs_method, rhs         call_rhs = rhs, rhs_method, lhs          if (             rhs_type is not _MISSING  # Do we care?             and rhs_type is not lhs_type  # Could RHS be a subclass?             and issubclass(rhs_type, lhs_type)  # RHS is a subclass!             and lhs_rmethod is not rhs_method  # Is __r*__ actually different?         ):             calls = call_rhs, call_lhs         elif lhs_type is not rhs_type:             calls = call_lhs, call_rhs         else:             calls = (call_lhs,)          for first_obj, meth, second_obj in calls:             if meth is _MISSING:                 continue             value = meth(first_obj, second_obj)             if value is not NotImplemented:                 return value         else:             exc = TypeError(                 f"unsupported operand type(s) for {operator}: {lhs_type!r} and {rhs_type!r}"             )             exc._binary_op = operator             raise exc

有了這段代碼,你可以將減法運(yùn)算定義為 _create_binary_op(“sub”, “-”),然后根據(jù)需要重復(fù)定義出其它運(yùn)算。

“如何理解Python的二元算術(shù)運(yùn)算”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

網(wǎng)頁(yè)名稱(chēng):如何理解Python的二元算術(shù)運(yùn)算
標(biāo)題URL:http://aaarwkj.com/article0/ipocio.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、搜索引擎優(yōu)化微信公眾號(hào)、網(wǎng)站排名、外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司
中文字幕制服国产精品| 欧美大片免费在线播放| 女同欲望一区二区三区久久| 91中文在线观看一区| 国产三级精品三级在线播放| 色噜噜人妻av中文字幕| 日本一区二区不卡高清| 欧美国产精品中文字幕| 91人妻互换一区二区| 日韩精品诱惑一区二区| 熟女亚洲一区精品久久| 日韩新片一区二区三区| 亚州无吗一区二区三区| 午夜性色在线视频福利| 天堂av影片在线观看| 国产成人综合亚洲欧美在线| 日韩看片一区二区三区高清| 国产成人精品一二三四区| 日韩欧美一区二区三区不卡在线| 91色老久久精品偷偷鲁无毒| 少妇高潮毛片免费看高潮| 亚洲精品啪啪一区二区| 久激情内射婷内射蜜桃| 午夜性生活免费在线观看| 久久久国产精品调教网站| 日韩三级精品一区二区| 亚洲欧洲久久激情久av| 日本中文字幕一区在线观看| 99久久免费中文字幕| 亚洲中文字幕乱码第一页| heyzo高清中文字幕在线| 精品毛片久久久久久久久| 精品综合亚洲中文字幕| 国产精品国产三级国产不产一地 | 在线看岛国毛片十八禁| 欧美精品国产精品久久| 日本亚洲中文字幕无吗| 免费人妻aⅴ中文字幕| 亚洲少妇午夜福利视频| 最新国产情侣夫妻激情| 亚洲国产精品性色av|