在Python這門語(yǔ)言中,有一些比較特殊的使用方法,主要用到的是雙下劃線開(kāi)始和結(jié)束,正是因?yàn)槿绱耍€有一個(gè)比較接地氣的名字,叫做雙下方法,感興趣的話,可以詳細(xì)的為大家進(jìn)行解答一下。
前言
大家在寫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__.MyClsobjectat0x105732250>。
不是因?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è)詳解。
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)算符的雙下方法
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
程序執(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.5位運(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為例,先寫__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)的字符串。
再寫__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]之前,防止不合法的取值。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/127647.html
摘要:本文重點(diǎn)了解數(shù)據(jù)模型和接口的概念掌握特殊方法的定義,作用和基本用法。一基本概念數(shù)據(jù)模型是數(shù)據(jù)特征的抽象,這里是對(duì)框架的描述。數(shù)據(jù)模型規(guī)范了自身構(gòu)建模塊的接口,模塊包括但不限于序列迭代器函數(shù)類和上下文管理器。 導(dǎo)語(yǔ):本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之緒論篇的重點(diǎn)知識(shí)及個(gè)人心得,以加深自己的理解。 本文重點(diǎn): 1、了解Python數(shù)據(jù)模型和接口的概念;2、掌握特殊方法的定義,作用和基...
摘要:前言數(shù)據(jù)模型其實(shí)是對(duì)框架的描述,它規(guī)范了這門語(yǔ)言自身構(gòu)件模塊的接口,這些模塊包括但不限于序列迭代器函數(shù)類和上下文管理器。上述類實(shí)現(xiàn)了方法,它可用于需要布爾值的上下文中等。但多虧了它是特殊方法,我們也可以把用于自定義數(shù)據(jù)類型。 《流暢的Python》筆記。本篇是Python進(jìn)階篇的開(kāi)始。本篇主要是對(duì)Python特殊方法的概述。 1. 前言 數(shù)據(jù)模型其實(shí)是對(duì)Python框架的描述,它規(guī)范了...
摘要:?jiǎn)栴}背景使用模擬實(shí)現(xiàn)文檔,頁(yè)面和的語(yǔ)法差異遇到問(wèn)題。文檔中的效果如下分析問(wèn)題報(bào)錯(cuò)信息寫的很明確,,是不被期望的。遇到問(wèn)題時(shí),解決思路可以考慮下轉(zhuǎn)義碼標(biāo)簽。 問(wèn)題背景 使用hexo+css模擬實(shí)現(xiàn)weex文檔,頁(yè)面Weex 和 Vue 2.x 的語(yǔ)法差異遇到問(wèn)題。 問(wèn)題描述 新建頁(yè)面,copy進(jìn)去內(nèi)容,hexo server運(yùn)行,控制臺(tái)報(bào)錯(cuò): FATAL Somethings wrong...
摘要:目錄自身的文件共享自身的文件共享方式方式方式方式服務(wù)器端服務(wù)器端客戶端客戶端自身的文件共享參考查看共享網(wǎng)絡(luò)映射網(wǎng)絡(luò)驅(qū)動(dòng)器到本地盤斷開(kāi)網(wǎng)絡(luò)映射重置所有網(wǎng)絡(luò)驅(qū)動(dòng)器方式網(wǎng)址服務(wù)端中文網(wǎng)服務(wù)端中文網(wǎng)它是一個(gè)綠 目錄 1.Win自身的文件共享 ?2.FTP方式 3.NFS方式 3.1?服務(wù)器端 ?3....
閱讀 911·2023-01-14 11:38
閱讀 878·2023-01-14 11:04
閱讀 740·2023-01-14 10:48
閱讀 1982·2023-01-14 10:34
閱讀 942·2023-01-14 10:24
閱讀 819·2023-01-14 10:18
閱讀 499·2023-01-14 10:09
閱讀 572·2023-01-14 10:02