網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
前言
大家在寫(xiě) Python 代碼的時(shí)候有沒(méi)有這樣的疑問(wèn)。
為什么數(shù)學(xué)中的+
號(hào),在字符串運(yùn)算中卻變成拼接功能,如'ab' + 'cd'
結(jié)果為abcd
;而*
號(hào)變成了重復(fù)功能,如'ab' * 2
結(jié)果為abab
。
為什么某些對(duì)象print
能輸出數(shù)據(jù),而print
自定義的類對(duì)象卻輸出一堆看不懂的代碼<__main__.MyCls object at 0x105732250>
。
不是因?yàn)橄到y(tǒng)做了特殊定制,而是 Python 中有一類特殊的方法,在某些特定的場(chǎng)合會(huì)自動(dòng)調(diào)用。如,在字符串類str
中定義了__add__
方法后,當(dāng)代碼遇到字符串相加'ab' + 'cd'
時(shí),就會(huì)自動(dòng)調(diào)用__add__
方法完成字符串拼接。
因?yàn)檫@類特殊方法的方法名都是以雙下劃線開(kāi)始和結(jié)束,所以又被稱為雙下方法。
Python 中的雙下方法很多,今天我們對(duì)它做個(gè)詳解。
Python中的雙下方法
1. init方法
__init__
的方法是很多人接觸的第一個(gè)雙下方法
。
class?A: ????def?__init__(self,?a): ????????self.a?=?a
當(dāng)調(diào)用A()
實(shí)例化對(duì)象的時(shí)候,__init__
方法會(huì)被自動(dòng)調(diào)用,完成對(duì)象的初始化。
2. 運(yùn)算符的雙下方法
在類中定義運(yùn)算符相關(guān)的雙下方法
,可以直接在類對(duì)象上做加減乘除、比較等操作。
這里,定義一個(gè)尺子類Rule
,它包含一個(gè)屬性r_len
代表尺子的長(zhǎng)度。
class?Rule: ????def?__init__(self,?r_len): ????????self.r_len?=?r_len
2.1 比較運(yùn)算符
如果想按照尺子的長(zhǎng)度對(duì)不同的尺子做比較,需要在Rule
類中定義比較運(yùn)算符。
class?Rule: ????def?__init__(self,?r_len): ????????self.r_len?=?r_len ????#?<?運(yùn)算符 ????def?__lt__(self,?other): ????????return?self.r_len?<?other.r_len ????#?<=?運(yùn)算符 ????def?__le__(self,?other): ????????return?self.r_len?<=?other.r_len ????#?>?運(yùn)算符 ????def?__gt__(self,?other): ????????return?self.r_len?>?other.r_len ????#?>=?運(yùn)算符 ????def?__ge__(self,?other): ????????return?self.r_len?>=?other.r_len
這里定義了<
、<=
、>
和>=
四個(gè)比較運(yùn)算符,這樣就可以用下面的代碼比較Rule
對(duì)象了。
rule1?=?Rule(10) rule2?=?Rule(5) print(rule1?>?rule2)??#?True print(rule1?>=?rule2)??#?True print(rule1?<?rule2)??#?False print(rule1?<=?rule2)??#?False
當(dāng)用>
比較rule1
和rule2
的時(shí)候,rule1
對(duì)象會(huì)自動(dòng)調(diào)用__gt__
方法,并將rule2
對(duì)象傳給other
參數(shù),完成比較。
下面是比較運(yùn)算符的雙下方法
比較運(yùn)算符雙下方法
2.2 算術(shù)運(yùn)算符
可以支持類對(duì)象加減乘除。
def?__add__(self,?other): ????return?Rule(self.r_len?+?other.r_len)
這里定義了__add__
方法,對(duì)應(yīng)的是+
運(yùn)算符,他會(huì)把兩個(gè)尺子的長(zhǎng)度相加,并生成新的尺子。
rule1?=?Rule(10) rule2?=?Rule(5) rule3?=?rule1?+?rule2
下面是算術(shù)運(yùn)算符的雙下方法
2.3 反向算術(shù)運(yùn)算符
它支持其他類型的變量與Rule
類相加。以__radd__
方法為例
def?__radd__(self,?other): ????return?self.r_len?+?other
rule1?=?Rule(10) rule2?=?10?+?rule1
程序執(zhí)行10 + rule1
時(shí),會(huì)嘗試調(diào)用int
類的__add__
但int
類類沒(méi)有定義與Rule
類對(duì)象相加的方法,所以程序會(huì)調(diào)用+
號(hào)右邊對(duì)象rule1
的__radd__
方法,并把10
傳給other
參數(shù)。
所以這種運(yùn)算符又叫右加運(yùn)算符。它所支持的運(yùn)算符與上面的算術(shù)運(yùn)算符一樣,方法名前加r
即可。
2.4 增量賦值運(yùn)算符
增量賦值運(yùn)算符是+=
、-=
、*=
、/=
等。
def?__iadd__(self,?other): ????self.r_len?+=?other ????return?self
rule1?=?Rule(10) rule1?+=?5
除了__divmod__
方法,其他的跟算數(shù)運(yùn)算符一樣,方面名前都加i。
2.4 位運(yùn)算符
這部分支持按二進(jìn)制進(jìn)行取反、移位和與或非等運(yùn)算。由于Rule
類不涉及位運(yùn)算,所以我們換一個(gè)例子。
定義二進(jìn)制字符串的類BinStr
,包含bin_str
屬性,表示二進(jìn)制字符串。
class?BinStr: ????def?__init__(self,?bin_str): ????????self.bin_str?=?bin_str
x?=?BinStr('1010')??#創(chuàng)建二進(jìn)制字符串對(duì)象 print(x.bin_str)?#?1010
給BinStr
定義一個(gè)取反運(yùn)算符~
#?~?運(yùn)算符 def?__invert__(self): ????inverted_bin_str?=?''.join(['1'?if?i?==?'0'?else?'0'?for?i?in?self.bin_str]) ????return?BinStr(inverted_bin_str)
__invert__
方法中,遍歷bin_str
字符串,將每位取反,并返回一個(gè)新的BinStr
類對(duì)象。
x?=?BinStr('1011') invert_x?=?~x print(invert_x.bin_str)?#?0100
下面是位運(yùn)算符的雙下方法
這部分也支持反向位運(yùn)算符和增量賦值位運(yùn)算符,規(guī)則跟算數(shù)運(yùn)算符一樣,這里就不再贅述。
3.字符串表示
這部分涉及兩個(gè)雙下方法__repr__
和__format__
,在某些特殊場(chǎng)景,如print
,會(huì)自動(dòng)調(diào)用,將對(duì)象轉(zhuǎn)成字符串。
還是以BinStr
為例,先寫(xiě)__repr__
方法。
def?__repr__(self): ????decimal?=?int('0b'+self.bin_str,?2) ????return?f'二進(jìn)制字符串:{self.bin_str},對(duì)應(yīng)的十進(jìn)制數(shù)字:{decimal}'
x?=?BinStr('1011') print(x) #?輸出:二進(jìn)制字符串:1011,對(duì)應(yīng)的十進(jìn)制數(shù)字:11
當(dāng)程序執(zhí)行print(x)
時(shí),會(huì)自動(dòng)調(diào)用__repr__
方法,獲取對(duì)象x
對(duì)應(yīng)的字符串。
再寫(xiě)__format__
方法,它也是將對(duì)象格式化為字符串。
def?__format__(self,?format_spec): ????return?format_spec?%?self.bin_str
print('{0:二進(jìn)制字符串:%s}'.format(x)) #?輸出:二進(jìn)制字符串:1011
當(dāng).format
方法的前面字符串里包含0:
時(shí),就會(huì)自動(dòng)調(diào)用__format__
方法,并將字符串傳給format_spec
參數(shù)。
4.數(shù)值轉(zhuǎn)換
調(diào)用int(obj)
、float(obj)
等方法,可以將對(duì)象轉(zhuǎn)成相對(duì)應(yīng)數(shù)據(jù)類型的數(shù)據(jù)。
def?__int__(self): ????return?int('0b'+self.bin_str,?2)
x?=?BinStr('1011') print(int(x))
當(dāng)調(diào)用int(x)
時(shí),會(huì)自動(dòng)調(diào)用__int__
方法,將二進(jìn)制字符串轉(zhuǎn)成十進(jìn)制數(shù)字。
數(shù)值轉(zhuǎn)換除了上面的兩個(gè)外,還有__abs__
、__bool__
、__complex__
、__hash__
、__index__
和__str__
。
__str__
和__repr__
一樣,在print
時(shí)都會(huì)被自動(dòng)調(diào)用,但__str__
優(yōu)先級(jí)更高。
5.集合相關(guān)的雙下方法
這部分可以像集合那樣,定義對(duì)象長(zhǎng)度、獲取某個(gè)位置元素、切片等方法。
以__len__
和__getitem__
為例
def?__len__(self): ????return?len(self.bin_str) def?__getitem__(self,?item): ????return?self.bin_str[item]
x?=?BinStr('1011') print(len(x))??#?4 print(x[0])??#?1 print(x[0:3])??#?101
len(x)
會(huì)自動(dòng)調(diào)用__len__
返回對(duì)象的長(zhǎng)度。
通過(guò)[]
方式獲取對(duì)象的元素時(shí),會(huì)自動(dòng)調(diào)用__getitem__
方法,并將切片對(duì)象傳給item
參數(shù),即可以獲取單個(gè)元素,還可以獲取切片。
集合相關(guān)的雙下方法還包括__setitem__
、__delitem__
和__contains__
。
6.迭代相關(guān)的雙下方法
可以在對(duì)象上使用for-in
遍歷。
def?__iter__(self): ????self.cur_i?=?-1 ????return?self def?__next__(self): ????self.cur_i?+=?1 ????if?self.cur_i?>=?len(self.bin_str): ????????raise?StopIteration()??#?退出迭代 ????return?self.bin_str[self.cur_i]
x?=?BinStr('1011') for?i?in?x: ????print(i)
當(dāng)在x
上使用for-in
循環(huán)時(shí),會(huì)先調(diào)用__iter__
方法將游標(biāo)cur_i
置為初始值-1
,然后不斷調(diào)用__next__
方法遍歷self.bin_str
中的每一位。
這部分還有一個(gè)__reversed__
方法用來(lái)反轉(zhuǎn)對(duì)象。
def?__reversed__(self): ????return?BinStr(''.join(list(reversed(self.bin_str))))
x?=?BinStr('1011') reversed_x?=?reversed(x) print(reversed_x) #?輸出:二進(jìn)制字符串:1101,對(duì)應(yīng)的十進(jìn)制數(shù)字:13
7.類相關(guān)的雙下方法
做 web 開(kāi)發(fā)的朋友,用類相關(guān)的雙下方法會(huì)更多一些。
7.1 實(shí)例的創(chuàng)建和銷毀
實(shí)例的創(chuàng)建是__new__
和__init__
方法,實(shí)例的銷毀是__del__
方法。
__new__
的調(diào)用早于__init__
,它的作用是創(chuàng)建對(duì)象的實(shí)例(內(nèi)存開(kāi)辟一段空間),而后才將該實(shí)例傳給__init__
方法,完成實(shí)例的初始化。
由于__new__
是類靜態(tài)方法,因此它可以控制對(duì)象的創(chuàng)建,從而實(shí)現(xiàn)單例模式。
__del__
方法在實(shí)例銷毀時(shí),被自動(dòng)調(diào)用,可以用來(lái)做一些清理工作和資源釋放的工作。
7.2 屬性管理
類屬性的訪問(wèn)和設(shè)置。包括__getattr__
、__getattribute__
、__setattr__
和__delattr__
方法。
__getattr__
和__getattribute__
的區(qū)別是,當(dāng)訪問(wèn)類屬性時(shí),無(wú)論屬性存不存在都會(huì)調(diào)用__getattribute__
方法,只有當(dāng)屬性不存在時(shí)才會(huì)調(diào)用__getattr__
方法。
7.3 屬性描述符
控制屬性的訪問(wèn),一般用于把屬性的取值控制在合理范圍內(nèi)。包括__get__
、__set__
和__delete__
方法。
class?XValidation: ????def?__get__(self,?instance,?owner): ????????return?self.x ????def?__set__(self,?instance,?value): ????????if?0?<=?value?<=?100: ????????????self.x?=?value ????????else: ????????????raise?Exception('x不能小于0,不能大于100') ????def?__delete__(self,?instance): ????????print('刪除屬性') class?MyCls: ????x?=?XValidation() ????def?__init__(self,?n): ????????self.x?=?n obj?=?MyCls(10) obj.x?=?101 print(obj.x)?#?拋異常:Exception: x不能小于0,不能大于100
上述例子,通過(guò)類屬性描述符,可以將屬性x的取值控制在[0, 100]
之前,防止不合法的取值。
8.總結(jié)
雖然上面介紹的不是所有的雙下方法,但也算是絕大多數(shù)了。
雖然雙下方法里可以編寫(xiě)任意代碼,但大家盡量編寫(xiě)與方法要求一樣的代碼。如,在__add__
方法實(shí)現(xiàn)的不是對(duì)象相加而是相減,雖然也能運(yùn)行,但這樣會(huì)造成很大困惑,不利于代碼維護(hù)。
原文鏈接:https://segmentfault.com/a/1190000042107956
相關(guān)推薦
- 2022-09-14 Flutter?iOS開(kāi)發(fā)OC混編Swift動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)問(wèn)題填坑_Swift
- 2022-09-19 Tomcat10配置端口號(hào)為443(使用https訪問(wèn))_Tomcat
- 2022-06-16 docker?maven?plugin快速部署微服務(wù)的詳細(xì)流程_docker
- 2022-06-06 ?Redis?串行生成順序編碼的方法實(shí)現(xiàn)_Redis
- 2022-04-02 C語(yǔ)言對(duì)冒泡排序進(jìn)行升級(jí)介紹_C 語(yǔ)言
- 2022-08-20 Python操作HDF5文件示例_python
- 2023-02-27 C語(yǔ)言中互斥鎖與自旋鎖及原子操作使用淺析_C 語(yǔ)言
- 2022-07-21 StreamX 部署 Flink Stream 應(yīng)用
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支