Python 正確重載運算符(增量賦值運算符)

增量賦值運算符

Vector 類已經支持增量賦值運算符 += 和 *= 了,如示例 13-15 所示。
示例 13-15 增量賦值不會修改不可變目標,而是新建實例,然后
重新綁定

>>> v1 = Vector([1, 2, 3])
>>> v1_alias = v1 # ?
>>> id(v1) # ?
4302860128
>>> v1 += Vector([4, 5, 6]) # ?
>>> v1 # ?
Vector([5.0, 7.0, 9.0])
>>> id(v1) # ?
4302859904
>>> v1_alias # ?
Vector([1.0, 2.0, 3.0])
>>> v1 *= 11 # ?
>>> v1 # ?
Vector([55.0, 77.0, 99.0])
>>> id(v1)
4302858336

? 復制一份,供后面審查 Vector([1, 2, 3]) 對象。
? 記住一開始綁定給 v1 的 Vector 實例的 ID。
? 增量加法運算。
? 結果與預期相符……
? ……但是創建了新的 Vector 實例。
? 審查 v1_alias,確認原來的 Vector 實例沒被修改。
? 增量乘法運算。
? 同樣,結果與預期相符,但是創建了新的 Vector 實例。

如果一個類沒有實現表 13-1 列出的就地運算符,增量賦值運算符只是
語法糖:a += b 的作用與 a = a + b 完全一樣。對不可變類型來說,
這是預期的行為,而且,如果定義了 __add__ 方法的話,不用編寫額
外的代碼,+= 就能使用。
然而,如果實現了就地運算符方法,例如 __iadd__,計算 a += b 的
結果時會調用就地運算符方法。這種運算符的名稱表明,它們會就地修
改左操作數,而不會創建新對象作為結果。

不可變類型,如 Vector 類,一定不能實現就地特殊方法。
這是明顯的事實,不過還是值得提出來。

為了展示如何實現就地運算符,我們將擴展示例 11-12 中的 BingoCage
類,實現 __add____iadd__ 方法。
我們把子類命名為 AddableBingoCage。示例 13-16 是我們想讓 + 運算
符具有的行為。

示例 13-16 使用 + 運算符新建 AddableBingoCage 實例

>>> vowels = 'AEIOU'
>>> globe = AddableBingoCage(vowels) ?
>>> globe.inspect()
('A', 'E', 'I', 'O', 'U')
>>> globe.pick() in vowels ?
True
>>> len(globe.inspect()) ?
4 >>> globe2 =
AddableBingoCage('XYZ') ?
>>> globe3 = globe + globe2
>>> len(globe3.inspect()) ?
7 >>> void =
globe +
[10, 20] ?
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'AddableBingoCage' and 'list'

? 使用 5 個元素(vowels 中的各個字母)創建一個 globe 實例。
? 從中取出一個元素,確認它在 vowels 中。
? 確認 globe 的元素數量減少到 4 個了。
? 創建第二個實例,它有 3 個元素。
? 把前兩個實例加在一起,創建第 3 個實例。這個實例有 7 個元素。
? AddableBingoCage 實例無法與列表相加,拋出 TypeError。那個
錯誤消息是 __add__ 方法返回 NotImplemented 時 Python 解釋器輸出
的。

AddableBingoCage 是可變的,實現 iadd 方法后的行為如示例
13-17 所示。

示例 13-17 可以使用 += 運算符載入現有的 AddableBingoCage
實例(接續示例 13-16)

>>> globe_orig = globe ?
>>> len(globe.inspect()) ?
4 >>> globe += globe2 ?
>>> len(globe.inspect())
7 >>> globe += ['M', '
N'] ?
>>> len(globe.inspect())
9 >>> globe is globe_orig ?
True
>>> globe += 1 ?
Traceback (most recent call last):
...
TypeError: right operand in += must be 'AddableBingoCage' or an iterable

? 復制一份,供后面檢查對象的標識。
? 現在 globe 有 4 個元素。
? AddableBingoCage 實例可以從同屬一類的其他實例那里接受元
素。
? += 的右操作數也可以是任何可迭代對象。
? 在這個示例中,globe 始終指代 globe_orig 對象。
? AddableBingoCage 實例不能與非可迭代對象相加,錯誤消息會指
明原因。

注意,與 + 相比,+= 運算符對第二個操作數更寬容。+ 運算符的兩個操
作數必須是相同類型(這里是 AddableBingoCage),如若不然,結果
的類型可能讓人摸不著頭腦。而 += 的情況更明確,因為就地修改左操
作數,所以結果的類型是確定的。

通過觀察內置 list 類型的工作方式,我確定了要對 + 和 +=
的行為做什么限制。 my_list + x 只能用于把兩個列表加到一
起,而 my_list += x 可以使用右邊可迭代對象 x 中的元素擴展左
邊的列表。list.extend() 的行為也是這樣的,它的參數可以是
任何可迭代對象。

我們明確了 AddableBingoCage 的行為,下面來看實現方式,如示例
13-18 所示。
示例 13-18 bingoaddable.py:AddableBingoCage 擴展
BingoCage,支持 + 和 +=

import itertools ?
from tombola import Tombola
from bingo import BingoCage
class AddableBingoCage(BingoCage): ?def __add__(self, other):if isinstance(other, Tombola): ?return AddableBingoCage(self.inspect() + other.inspect()) ?else:return NotImplementeddef __iadd__(self, other):if isinstance(other, Tombola):other_iterable = other.inspect() ?else:try:other_iterable = iter(other)except TypeError: ?self_cls = type(self).__name__msg = "right operand in += must be {!r} or an iterable"
raise TypeError(msg.format(self_cls))self.load(other_iterable) ?return self ?

? “PEP 8—Style Guide for Python
Code”(https://www.python.org/dev/peps/pep-0008/#imports)建議,把導
入標準庫的語句放在導入自己編寫的模塊之前。
? AddableBingoCage 擴展 BingoCage。
? add 方法的第二個操作數只能是 Tombola 實例。
? 如果 other 是 Tombola 實例,從中獲取元素。
? 否則,嘗試使用 other 創建迭代器。
? 如果嘗試失敗,拋出異常,并且告知用戶該怎么做。如果可能,錯
誤消息應該明確指導用戶怎么解決問題。
? 如果能執行到這里,把 other_iterable 載入 self。
? 重要提醒:增量賦值特殊方法必須返回 self。
通過示例 13-18 中 __add____iadd__ 返回結果的方式可以總結出就
地運算符的原理。

__add__

調用 AddableBingoCage 構造方法構建一個新實例,作為結果返
回。

iadd
把修改后的 self 作為結果返回。

最后,示例 13-18 中還有一點要注意:從設計上
看,AddableBingoCage 不用定義 __radd__ 方法,因為不需要。如果
右操作數是相同類型,那么正向方法 __add__ 會處理,因此,Python
計算 a + b 時,如果 a 是 AddableBingoCage 實例,而 b 不是,那么
會返回 NotImplemented,此時或許可以讓 b 所屬的類接手處理。可
是,如果表達式是 b + a,而 b 不是 AddableBingoCage 實例,返回
了 NotImplemented,那么 Python 最好放棄,拋出 TypeError,因為
無法處理 b。

一般來說,如果中綴運算符的正向方法(如 __mul__)只處
理與 self 屬于同一類型的操作數,那就無需實現對應的反向方法
(如 __rmul__),因為按照定義,反向方法是為了處理類型不同
的操作數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/85671.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/85671.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/85671.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

XCUITest + Objective-C 詳細示例

??親愛的技術愛好者們,熱烈歡迎來到 Kant2048 的博客!我是 Thomas Kant,很開心能在CSDN上與你們相遇~?? 本博客的精華專欄: 【自動化測試】 【測試經驗】 【人工智能】 【Python】

redis分布式鎖 Redisson在電商平臺開發中的實際應用

目錄 概述 Redis分布式鎖的實現方式 1. 基于SETNX命令(String類型) 2. 使用SET命令的NX和EX參數(推薦方式) 3. 基于Lua腳本實現復雜邏輯 4. RedLock算法(多節點Redis實現) Redisson的分布式鎖 Redis…

joomla 使用nginx服務器只能打開首頁,其他頁面404的解決方案

最近一個客戶將Joomla4網站從原先的Apache服務器改為Nginx服務器,整個過程一切順利,但還原網站后發現只能打開首頁,其他頁面都是404。這個問題需要修改nginx的配置文件來解決。 偽靜態 在Apache中使用.htaccess來完成偽靜態路由的轉發&…

湖北理元理律師事務所企業債務紓困路徑:司法重整中的再生之道

中小企業債務危機常呈現“擔保鏈擴散”特征,單一債務可能引發企業崩盤。湖北理元理律師事務所通過預重整制度與企業債務重組技術,探索出“司法保護商業談判”的紓困模式。 一、企業債務風險處置四步法 緊急止血 申請司法保護:通過訴前調解…

利用DeepWiki高效閱讀項目源碼

想獲取更多高質量的Java技術文章?歡迎訪問Java技術小館官網,持續更新優質內容,助力技術成長 技術小館官網 DeepWiki 是一個強大的工具,專為程序員提供開源項目源碼的結構化文檔和 AI 驅動的問答功能,幫助快速理解復雜…

django rest_framework 前端網頁實現Token認證

rest_framework提供了幾種認證方式:Session、Token等。Session是最簡單的,幾乎不用寫任何代碼就可以是實現,Token方式其實也不復雜,網上的教程一大把,但是最后都是用Postman這類工具來實現API調用的,通過這…

面試題-函數類型的重載是啥意思

在 TypeScript 中,函數重載(Function Overload) 是指為同一個函數提供多個不同的調用簽名(參數類型和返回值類型的組合),但函數體只有一個實現。這樣可以讓函數在不同的輸入下表現出不同的行為,…

磐基PaaS平臺MongoDB組件SSPL許可證風險與合規性分析(上)

#作者:任少近 文章目錄 1.背景與問題1.1.背景1.2.問題 3.SSPL條款解讀分析3.1.條款0:定義條款3.2.條款一:源代碼條款3.3.條款二:基本授權條款3.4.條款三:反規避保護條款3.5.條款四:逐字傳播條款3.6.條款五…

「Linux文件及目錄管理」輸入輸出重定向與管道

知識點解析 輸入/輸出重定向 標準輸入(stdin):默認從鍵盤讀取,文件描述符為0。標準輸出(stdout):默認輸出到終端,文件描述符為1。標準錯誤(stderr):默認輸出到終端,文件描述符為2。重定向符號: >:覆蓋輸出到文件(如command > file)。>>:追加輸出…

【Node】最佳Node.js后端開發模板推薦

Node.js 后端開發模板推薦 以下是幾個優秀的Node.js后端模板,它們都適合二次開發,各自有不同的特點和適用場景: 1. Express基礎模板 Express Generator (官方工具) 官方提供的快速搭建工具基礎MVC結構簡單易上手 npm install express-ge…

HALCON相機標定

相機標定簡介: 首先,相機會產生畸變,即實際圖像和拍攝圖像不一致,可以是凸性也可以是凹性形變,相機標定的過程就是將畸變圖像還原為原始圖像,并將圖像中的像素坐標轉換為世界坐標。 形如:相機內…

Solidity 入門教程(二):值類型全解 —— 布爾、整數、地址與字節數組

在上一章中,我們寫下了第一個 Solidity 合約并在 Remix 中成功運行。本章我們將深入了解 Solidity 中的幾種常用值類型(Value Types),并通過示例代碼在 Remix 進行驗證。 一、Solidity 中的三種數據類型 在 Solidity 中&#xf…

16.大數據監控

0.說明 監控主要構成。 軟件版本。 1.exporter監控配置 1.1 node_exporter 啟動命令 nohup ./node_exporter &服務 創建文件 /etc/systemd/system/node_exporter.service: [Unit] DescriptionPrometheus Node Exporter Wantsnetwork-online.target Aft…

Tomcat項目本地部署(Servlet為例)

在Windows上部署 在idea中打開項目 首先我們需要準備一個Servlet項目,我之前的Servlet項目是用eclipse寫的,這種情況下如果用idea直接打開的話會出現左側目錄無法顯示的情況,這個時候我們就需要用別的方法打開 打開項目管理 如下圖&#…

安裝MySQL 5.7導入數據,修改密碼,創建賬號并授權

1. 準備工作 sudo yum update -y sudo yum install -y wget libaio numactl 2. 下載 MySQL 5.7 二進制包 wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz 3. 創建 MySQL 用戶和組 sudo groupadd mysql sudo useradd -r -g m…

基礎RAG實現,最佳入門選擇(八)

RAG重排序 RAG重排序技術以提高RAG系統中的檢索質量。重新排序充當初始檢索后的第二個過濾步驟,以確保最相關的內容用于響應生成。 重排序的關鍵概念 1.初始檢索:使用基本相似度搜索的第一遍(準確度較低但速度更快) 2.文檔評分…

Spring Boot 常用注解整理

Spring & Spring Boot 常用注解整理 現代的 Spring 與 Spring Boot 應用大量使用注解來簡化配置、管理組件和實現各種框架功能。本文系統整理了常用的 Spring/Spring Boot 注解,按照功能分類進行介紹。每個注解都會涵蓋其含義、提供來源、應用場景以及代碼示例…

深入理解 Cross-Entropy 損失函數:從原理到實踐

在深度學習中,損失函數是衡量模型性能的關鍵指標之一。對于多分類問題,Cross-Entropy 損失函數 是最常用的選擇之一。它不僅能夠有效衡量模型輸出與真實標簽之間的差異,還能通過梯度下降法指導模型的優化。本文將深入探討 Cross-Entropy 損失…

Vim-vimrc保存文件自動移除行末尾空格

Vim-vimrc保存文件自動移除行末尾空格 這段代碼通過設置 autocmd 和自定義函數,確保每次保存文件時都自動刪除文件中的行尾空格,同時不會影響光標和視圖的位置。它適用于所有文件類型,并且刪除操作不會引入錯誤,即使沒有行尾空格的…

Occt幾何內核快速入門

本文簡單介紹 Open Cascade Technology(OCCT),提供了下載地址和文檔地址。通過OCCT的測試工具Draw,展示了OCCT的一些功能特性。介紹了OCCT集成開發的演示代碼,提供了源代碼下載地址和編譯過程文件。 一、簡介 Open C…