Python實(shí)用教程_spiritx的博客-CSDN博客
什么是魔術(shù)方法?
所有以雙下劃線__
包起來(lái)的方法,統(tǒng)稱為Magic Method(魔術(shù)方法),它是一種的特殊方法,普通方法需要調(diào)用,而魔術(shù)方法不需要顯示調(diào)用就可以執(zhí)行。
魔術(shù)方法在類或?qū)ο蟮哪承┦录霭l(fā)后會(huì)自動(dòng)執(zhí)行,讓類具有神奇的“魔力”。如果希望根據(jù)自己的程序定制自己特殊功能的類,那么就需要對(duì)這些方法進(jìn)行重寫。
常見(jiàn)的魔術(shù)方法
__init__(self)
初始化方法
觸發(fā)機(jī)制:實(shí)例化對(duì)象之后立即觸發(fā)
參數(shù):至少有一個(gè)self,接收當(dāng)前對(duì)象,其他參數(shù)根據(jù)需要進(jìn)行定義
返回值:無(wú)
作用:初始化對(duì)象的成員
# __init__示例
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.x, p.y) # 輸出: 1 2
__new__(cls)
構(gòu)造方法
觸發(fā)時(shí)機(jī): 實(shí)例化對(duì)象時(shí)自動(dòng)觸發(fā)(在__init__之前觸發(fā))
參數(shù):至少一個(gè)cls 接收當(dāng)前類,其他參數(shù)根據(jù)初始化方法參數(shù)決定
返回值:必須返回一個(gè)對(duì)象實(shí)例,沒(méi)有返回值,則實(shí)例化對(duì)象的結(jié)果為None
作用:實(shí)例化對(duì)象
注意:實(shí)例化對(duì)象是Object類底層實(shí)現(xiàn),其他類繼承了Object的__new__才能夠?qū)崿F(xiàn)實(shí)例化對(duì)象。
class Person(object):
def __init__(self):
print('__init__(): 我也被調(diào)用啦~')
def __new__(cls, *args, **kwargs): # 重寫后,不再創(chuàng)建對(duì)象
print('__new__(): 哈哈我被調(diào)用啦~')
>>> per = Person()
__new__(): 哈哈我被調(diào)用啦~
>>> print(per)
None
class Person(object):
def __init__(self):
print('__init__(): 我也被調(diào)用啦~')
def __new__(cls, *args, **kwargs):
print('__new__(): 哈哈我被調(diào)用啦~')
ret = super().__new__(cls) # 調(diào)用父類object的__new__方法創(chuàng)建對(duì)象
return ret
>>> per = Person()
__new__(): 哈哈我被調(diào)用啦~
__init__(): 我也被調(diào)用啦~
>>> print(per)
<__main__.Person object at 0x0000020FA3892848>
class Test:
def __new__(cls, *args, **kwargs):
print("我是__new__方法")
obj = object.__new__(cls)
print(obj)
return obj
def __init__(self):
print(self)
print("我是__init__方法")
if __name__ == '__main__':
a = Test()
-------輸出結(jié)果---------
我是__new__方法
<__main__.Test object at 0x123902f70>
<__main__.Test object at 0x123902f70>
我是__init__方法
上面示例會(huì)發(fā)現(xiàn):
1)__new__魔術(shù)方法返回的就是self的內(nèi)存地址;
2)如果不在__new__方法里面調(diào)object的__new__方法就不會(huì)創(chuàng)建對(duì)象,__init__不會(huì)被執(zhí)行;
3)如果不在__new__方法里面return創(chuàng)建好的對(duì)象,__init__不會(huì)被執(zhí)行;
事實(shí)上,當(dāng)我們理解了new方法后,我們還可以利用它來(lái)做一些其他有趣的事情,比如實(shí)現(xiàn) 設(shè)計(jì)模式中的 單例模式(singleton)
依照Python官方文檔的說(shuō)法,new方法主要是當(dāng)你繼承一些不可變的class時(shí)(比如int, str, tuple), 提供給你一個(gè)自定義這些類的實(shí)例化過(guò)程的途徑。還有就是實(shí)現(xiàn)自定義的metaclass
這個(gè)方法我們一般很少定義,不過(guò)我們?cè)谝恍╅_(kāi)源框架中偶爾會(huì)遇到定義這個(gè)方法的類。實(shí)際上,這才是"真正的構(gòu)造方法",它會(huì)在對(duì)象實(shí)例化時(shí)第一個(gè)被調(diào)用,然后再調(diào)用init,它們的區(qū)別主要如下:
- new的第一個(gè)參數(shù)是cls,而init的第一個(gè)參數(shù)是self
- new返回值是一個(gè)實(shí)例,而init沒(méi)有任何返回值,只做初始化操作
- new由于是返回一個(gè)實(shí)例對(duì)象,所以它可以給所有實(shí)例進(jìn)行統(tǒng)一的初始化操作
由于new優(yōu)先于init調(diào)用,且返回一個(gè)實(shí)例,所以我們可以利用這種特性,每次返回同一個(gè)實(shí)例來(lái)實(shí)現(xiàn)一個(gè)單例類:
?
__del__(self)
析構(gòu)方法
觸發(fā)時(shí)機(jī):當(dāng)該類對(duì)象被銷毀時(shí),自動(dòng)觸發(fā)
參數(shù):一個(gè)self,接受當(dāng)前對(duì)象
返回值:無(wú)
作用:關(guān)閉或釋放對(duì)象創(chuàng)建時(shí)資源
注意:del不一定會(huì)觸發(fā)當(dāng)前方法,只有當(dāng)前對(duì)象沒(méi)有任何變量引用時(shí)才會(huì)觸發(fā)
class Cat:
def eat(self):
print("我嘎嘎能吃")
def __del__(self):
print("ohohoh,我被銷毀了”)
print("<=======start======>")
cat1 = Cat()
print("<=======ends======>”)
‘’‘
<=======start======>
<=======ends======>
ohohoh,我被銷毀了
’‘’
出現(xiàn)上面現(xiàn)象的原因是在沒(méi)有手動(dòng)執(zhí)行del
的情況下,程序執(zhí)行結(jié)束后自動(dòng)觸發(fā)析構(gòu)方法。
繼續(xù),現(xiàn)在加一個(gè)實(shí)例化,并且我們del
cat1:
cat1 = Cat()
cat2 = cat1
print("<=======start======>")
del cat1
print("<=======ends======>”)
‘’’
<=======start======>
<=======ends======>
ohohoh,我被銷毀了
’‘’
既然我們?cè)趕tart與end中間刪除了cat1,為啥程序還是在執(zhí)行完后觸發(fā)析構(gòu)方法?這主要是因?yàn)閏at2還在繼續(xù)占用cat1的內(nèi)存地址,所以會(huì)在cat2執(zhí)行完畢后觸發(fā)析構(gòu)方法。
只要同時(shí)刪除cat1和cat2,內(nèi)存地址沒(méi)有指向的值,這塊內(nèi)存被釋放就會(huì)觸發(fā)析構(gòu)方法:
cat1 = Cat()
cat2 = cat1
print("<=======start======>")
del cat1
del cat2
print("<=======ends======>”)
‘’’
<=======start======>
ohohoh,我被銷毀了
<=======ends======>
’’’
__call__(self)
可調(diào)用對(duì)象魔術(shù)方法
觸發(fā)時(shí)機(jī):將對(duì)象當(dāng)作函數(shù)調(diào)用時(shí)觸發(fā),方式: 對(duì)象()
參數(shù):至少一個(gè)self接收對(duì)象,其余根據(jù)調(diào)用時(shí)參數(shù)決定
返回值:根據(jù)情況而定
作用:可以將復(fù)雜的步驟進(jìn)行合并操作,減少調(diào)用的步驟,方便使用
注意:無(wú)
class A(object):
def __call__(self, *args, **kwargs):
print('call....')
a = A()
a() # 自動(dòng)調(diào)用__call__()
class Fibonacci(object):
def __call__(self, num):
a, b = 1, 1
lst = []
if num <= 2:
lst.append(a)
lst.append(b)
else:
for i in range(num):
lst.append(a)
a, b = b, a + b
return lst
>>> f = Fibonacci()
>>> print(f(5))
[1, 1, 2, 3, 5]
__str__(self)
需要對(duì)象轉(zhuǎn)換為string時(shí),python都會(huì)默認(rèn)調(diào)用該魔法方法,如print的時(shí)候,與字符串進(jìn)行+運(yùn)算的時(shí)候,凡是需要進(jìn)行隱示類型轉(zhuǎn)換為字符串的地方,都會(huì)自動(dòng)調(diào)用該方法。該方法返回一個(gè)字符串:
class Dog(object):
def __init__(self,name):#self 是對(duì)象
#對(duì)象.屬性名 = 屬性值
self.name = name
def __str__(self):
#必須返回一個(gè)字符串
return f"小狗的名字是{self.name}"
dog1 = Dog('aha')
print(dog1)
#str = 'Hello!' + dog1; #會(huì)提示TypeError
str = 'Hello!' + str(dog1);
print(f'{str=}’)
‘’'
小狗的名字是aha
str='Hello!小狗的名字是aha’
‘''
__repr__(self)
函數(shù)str() 用于將值轉(zhuǎn)化為適于人閱讀的形式,而repr() 轉(zhuǎn)化為供解釋器讀取的形式,某對(duì)象沒(méi)有適于人閱讀的解釋形式的話,str() 會(huì)返回與repr(),所以print展示的都是str的格式。
我們經(jīng)常會(huì)直接輸出類的實(shí)例化對(duì)象.
class Coo:
def __init__(self):
self.name = ""
self.add = "python.org"
def __repr__(self):
return "[name="+ self.name +",add=" + self.add +"]"
co = Coo()
print(co)
‘’'
[name=,add=python.org]
‘''
由此可見(jiàn),__repr__() 方法是類的實(shí)例化對(duì)象用來(lái)做“自我介紹”的方法,默認(rèn)情況下,它會(huì)返回當(dāng)前對(duì)象的“類名+object at+內(nèi)存地址”,而如果對(duì)該方法進(jìn)行重寫,可以為其制作自定義的自我描述信息。
__repr__
和__str__
這兩個(gè)方法都是用于顯示的,__str__
是面向用戶的,而__repr__
面向程序員。
- 打印操作會(huì)首先嘗試
__str__
和str內(nèi)置函數(shù)(print運(yùn)行的內(nèi)部等價(jià)形式),它通常應(yīng)該返回一個(gè)友好的顯示。 -
__repr__
用于所有其他的環(huán)境中:用于交互模式下提示回應(yīng)以及repr函數(shù),如果沒(méi)有使用__str__
,會(huì)使用print和str。它通常應(yīng)該返回一個(gè)編碼字符串,可以用來(lái)重新創(chuàng)建對(duì)象,或者給開(kāi)發(fā)者詳細(xì)的顯示。
當(dāng)我們想所有環(huán)境下都統(tǒng)一顯示的話,可以重構(gòu)__repr__
方法;當(dāng)我們想在不同環(huán)境下支持不同的顯示,例如終端用戶顯示使用__str__
,而程序員在開(kāi)發(fā)期間則使用底層的__repr__
來(lái)顯示,實(shí)際上__str__
只是覆蓋了__repr__
以得到更友好的用戶顯示。
# __str__和__repr__示例
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old"
def __repr__(self):
return f"Person('{self.name}', {self.age})"
p = Person("Alice", 25)
print(str(p)) # 輸出: Alice is 25 years old
print(repr(p)) # 輸出: Person('Alice', 25)
__del__(self)
析構(gòu)函數(shù),對(duì)象在內(nèi)存中被銷毀刪除的時(shí)候會(huì)自動(dòng)調(diào)用__del__
?方法。
會(huì)在以下兩個(gè)場(chǎng)景被調(diào)用:
1、程序代碼運(yùn)行結(jié)束,在程序運(yùn)行過(guò)程中,創(chuàng)建的所有對(duì)象和變量都會(huì)被刪除銷毀
2、使用del變量
,將這個(gè)對(duì)象的引用計(jì)數(shù)變?yōu)?,會(huì)自動(dòng)調(diào)用del方法
class Star(object):
def __init__(self, name, movie):
self.name = name # 成員屬性 明星姓名
self.movie = movie # 成員屬性 明星的電影
# 成員方法
def playing(self):
print(f"{self.name} 出演了電影 {self.movie} !")
def __str__(self):
# 打印對(duì)象時(shí)顯示,
return f"{self.name} 是我的偶像,我非常喜歡他的電影 {self.movie}"
def __del__(self):
# 刪除對(duì)象時(shí)顯示
print(f"我現(xiàn)在不喜歡 {self.name} 了")
s1 = Star('周星馳', '大話西游')
print(s1)
del s1
s2 =Star('周慧敏', '賭圣風(fēng)云')
print(s2)
print('---game over—')
‘’'
周星馳 是我的偶像,我非常喜歡他的電影 大話西游
我現(xiàn)在不喜歡 周星馳 了
周慧敏 是我的偶像,我非常喜歡他的電影 賭圣風(fēng)云
---game over--
我現(xiàn)在不喜歡 周慧敏 了
‘''
__len__(self)
len(obj)函數(shù)調(diào)用時(shí),對(duì)象會(huì)自動(dòng)調(diào)用__len()__方法
import collections
card = collections.namedtuple('card', ["rank", 'suit'])
class FrenchDeck:
ranks = [ str(n) for n in range(2, 11)] + list("JQKA")
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [card(rank, suit) for suit in self.suits for rank in self.ranks]
def __len__(self):
return len(self._cards)
fd = FrenchDeck()
print('len(fd)=', len(fd)) # 可以直接使用len函數(shù)查看fd對(duì)象的長(zhǎng)度 52
__getitem__(self,item)
擁有此方法的對(duì)象可以通過(guò)的使用列表的形式進(jìn)行對(duì)象操作,如:切片,下標(biāo)取值.
import collections
card = collections.namedtuple('card', ["rank", 'suit'])
class FrenchDeck:
ranks = [ str(n) for n in range(2, 11)] + list("JQKA")
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [card(rank, suit) for suit in self.suits for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, item):
return self._cards[item]
fd = FrenchDeck()
print('fd[0]=', fd[0]) # 可以直接使用下表取值
for i in range(0, len(fd)):
print(fd[i])
特別注意,雖然可以通過(guò)循環(huán)的形式取出對(duì)象中值,但并不代表它是一個(gè)可迭代對(duì)象,即使你在方法中返回的是字符串也可以循環(huán),不過(guò)字符串循環(huán)會(huì)一直無(wú)限循環(huán)下去,直到你手動(dòng)停止。主要原因是,因?yàn)樵谑褂肙bj[key]時(shí),python解釋器自動(dòng)幫你調(diào)用了__getitem__(self,item)方法,所以只要不使用item這個(gè)參數(shù),無(wú)論你傳什么參數(shù)都不會(huì)報(bào)錯(cuò),返回什么值是有你決定的.
>>> isinstance(fd, collections.Iterable)
False
__cmp__(self,other)
用實(shí)例自身self和傳入的實(shí)例other進(jìn)行比較,如果self應(yīng)該排在前面,就返回 -1,如果other應(yīng)該排在前面,就返回1,如果兩者相當(dāng),返回 0。
最后可以用list.sort函數(shù)或者sorted函數(shù)來(lái)實(shí)現(xiàn)排序。
class Student(object):
def __init__(self):
self.grade = 0
def __cmp__(self,other):
if self.grade<other.grade:
return -1
elif self.grade>other.grade:
return 1
else:
return 0
__bool__(self)
觸發(fā)時(shí)機(jī): 使用bool(對(duì)象)的時(shí)候觸發(fā)
參數(shù):一個(gè)self接收對(duì)象
返回值:必須是布爾值
作用:根據(jù)實(shí)際情況決定,可以作為快捷方式使用
注意:僅適合于返回布爾值的操作
class A:
print("__bool__和__len__都未定義,bool調(diào)用恒為True")
print(bool(A()))
#__bool__和__len__都未定義,bool調(diào)用恒為True
#True
class B:
def __bool__(self):
print("__bool__返回False,bool調(diào)用恒為False")
return False
print(bool(B()))
#__bool__返回False,bool調(diào)用恒為False
#False
class C:
def __len__(self):
print("__bool__未定義,找到__len__,__len__返回值非0,bool調(diào)用恒為True")
return 1
print(bool(C()))
#__bool__未定義,找到__len__,__len__返回值非0,bool調(diào)用恒為True
#True
# 定義空字典
a = {}
# 定義空列表
b = []
# 定義空元組
c = ()
# 以后判斷這個(gè)3種數(shù)據(jù)類型是否有返回值直接通過(guò)bool方法來(lái)判斷
if not bool(a):
print("a為空字典")
if not bool(b):
print("b為空列表")
if not bool(c):
print("c為空元組")
‘’'
a為空字典
b為空列表
c為空元組
‘''
__format__(self)
觸發(fā)時(shí)機(jī):使用字符串.format(對(duì)象)時(shí)候觸發(fā)
參數(shù):一個(gè)self接收對(duì)象,一個(gè)參數(shù)接收f(shuō)ormat的{}中的格式,例如:>5
返回值:必須是字符串
作用:設(shè)置對(duì)象可以作為format的參數(shù),并且自定義對(duì)象格式化的規(guī)則
注意:無(wú)
__hash__(self)
調(diào)用hash函數(shù)時(shí)
class A:
def __init__(self):
self.a = 'a'
self.b = 'b'
def __hash__(self):
return 1
print(hash(A())) #1
print(hash(A())) #1
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __hash__(self):
return hash((self.name, self.age))
def __eq__(self, other):
if isinstance(other, Person):
return self.name == other.name and self.age == other.age
return False
# 創(chuàng)建對(duì)象
person1 = Person("John", 30)
person2 = Person("Alice", 25)
# 輸出哈希值
print(f"對(duì)象person1的hash值 {hash(person1)}”) #對(duì)象person1的hash值 2511066681118794660
print(f"對(duì)象person2的hash值 {hash(person2)}”) #對(duì)象person2的hash值 -7352762741811000521
# 比較對(duì)象相等性
print(f"person1和person2相等是否成立 {person1 == person2}”) #對(duì)象person2的hash值 -7352762741811000521
__add__(self,other)
實(shí)例只見(jiàn)的加法運(yùn)算
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
‘’’
Vector(7,8)
’‘’
運(yùn)算符魔術(shù)方法
重載運(yùn)算魔法函數(shù)定義 | 魔法函數(shù)說(shuō)明 |
__add__(self,other) | 實(shí)例之間的加法運(yùn)算+ |
__sub__(self,other) | 實(shí)例之間的減法運(yùn)算- |
__mul__(self,other) | 實(shí)例之間的乘法運(yùn)算* |
__truediv__(self,other) | 類與類之間的真除。只有from?future?import division之后它才有效/ |
__floordiv__(self,other) | 類與類之間的浮點(diǎn)除法運(yùn)算// |
__mod__(self,other) | 類與類之間的取余運(yùn)算% |
__pow__(self,other[,module])) | 類與類之間的指數(shù)運(yùn)算** |
__and__(self,other) | 類與類之間的按位與運(yùn)算& |
__xor__(self,other) | 類與類之間的按位異或運(yùn)算^ |
__or__(self,other) | 類與類之間的按位或運(yùn)算| |
__lt__(self,other) | 定義了比較操作符< |
__gt__(self,other) | 定義了比較操作符> |
__le__(self,other) | 定義了比較操作符<= |
__ge__(self,other) | 定義了比較操作符>= |
__eq__(self,other) | 定義了比較操作符== |
__ne__(self,other) | 定義了比較操作符!= |
__setitem__(self, key, value) | 使用self[nkey] = value賦值容器中的一項(xiàng) |
__delitem__(self, key) | 刪除self[nkey]。 |
例子:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Point(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Point(self.x * scalar, self.y * scalar)
def __truediv__(self, scalar):
return Point(self.x / scalar, self.y / scalar)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
p1 = Point(1, 2)
p2 = Point(3, 4)
# 加法操作
p3 = p1 + p2
print(p3.x, p3.y) # 輸出: 4, 6
# 減法操作
p4 = p1 - p2
print(p4.x, p4.y) # 輸出: -2, -2
# 乘法操作
p5 = p1 * 2
print(p5.x, p5.y) # 輸出: 2, 4
# 除法操作
p6 = p1 / 2
print(p6.x, p6.y) # 輸出: 0.5, 1.0
# 等值比較操作
print(p1 == p2) # 輸出: False
print(p1 == Point(1, 2)) # 輸出: True
# __lt__和__eq__示例
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __lt__(self, other):
return self.age < other.age
def __eq__(self, other):
return self.age == other.age
p1 = Person("Alice", 25)
p2 = Person("Bob", 30)
p3 = Person("Charlie", 25)
print(p1 < p2) # 輸出: True
print(p1 == p3) # 輸出: True
反運(yùn)算魔術(shù)方法
反運(yùn)算魔法方法,與算術(shù)運(yùn)算符保持一一對(duì)應(yīng),不同之處就是反運(yùn)算的魔法方法多了一個(gè)“r”。當(dāng)文件左操作不支持相應(yīng)的操作時(shí)被調(diào)用。
- radd(self, other)定義加法的行為:+
- rsub(self, other)定義減法的行為:-
- rmul(self, other)定義乘法的行為:*
- rtruediv(self, other)定義真除法的行為:/
- rfloordiv(self, other)定義整數(shù)除法的行為://
- rmod(self, other) 定義取模算法的行為:%
- rdivmod(self, other)定義當(dāng)被 divmod() 調(diào)用時(shí)的行為
- divmod(a, b)把除數(shù)和余數(shù)運(yùn)算結(jié)果結(jié)合起來(lái),返回一個(gè)包含商和余數(shù)的元組(a // b, a % b)。
- rpow(self, other[, module])定義當(dāng)被 power() 調(diào)用或 ** 運(yùn)算時(shí)的行為
- rlshift(self, other)定義按位左移位的行為:<<
- rrshift(self, other)定義按位右移位的行為:>>
- rand(self, other)定義按位與操作的行為:&
- rxor(self, other)定義按位異或操作的行為:^
-
ror(self, other)定義按位或操作的行為:|
a + b
這里加數(shù)是a,被加數(shù)是b,因此是a主動(dòng),反運(yùn)算就是如果a對(duì)象的__add__()方法沒(méi)有實(shí)現(xiàn)或者不支持相應(yīng)的操作,那么 Python 就會(huì)調(diào)用b的__radd__()方法。
class Nint(int):
def __add__(self, other):
print('__add()__')
return int.__add__(self, other)
def __radd__(self, other):
print('__radd()__')
return int.__sub__(other, self) # 注意 self 在后面
a = Nint(5)
b = Nint(3)
print(a + b) # 8
print('####')
print(1 + b) # -2
‘’'
__add()__
8
####
__radd()__
-2
‘''
賦值運(yùn)算符魔術(shù)方法
- iadd(self, other)定義賦值加法的行為:+=
- isub(self, other)定義賦值減法的行為:-=
- imul(self, other)定義賦值乘法的行為:*=
- itruediv(self, other)定義賦值真除法的行為:/=
- ifloordiv(self, other)定義賦值整數(shù)除法的行為://=
- imod(self, other)定義賦值取模算法的行為:%=
- ipow(self, other[, modulo])定義賦值冪運(yùn)算的行為:**=
- ilshift(self, other)定義賦值按位左移位的行為:<<=
- irshift(self, other)定義賦值按位右移位的行為:>>=
- iand(self, other)定義賦值按位與操作的行為:&=
- ior(self, other)定義賦值按位或操作的行為:|=
- ixor(self, other)定義賦值按位異或操作的行為:^=
一元運(yùn)算符魔術(shù)方法
- neg(self)定義正號(hào)的行為:+x
- pos(self)定義負(fù)號(hào)的行為:-x
- abs(self)定義當(dāng)被abs()調(diào)用時(shí)的行為
- invert(self)定義按位求反的行為:~x
屬性訪問(wèn)魔術(shù)方法
__getattr__(self, name)
定義當(dāng)用戶試圖獲取一個(gè)不存在的屬性時(shí)的行為。
觸發(fā)時(shí)機(jī):獲取不存在的對(duì)象成員時(shí)觸發(fā)
參數(shù):一個(gè)是接收當(dāng)前對(duì)象的self,一個(gè)是獲取成員名稱的字符串
返回值:必須有值
作用:為訪問(wèn)不存在的屬性設(shè)置值
注意:getattribute無(wú)論何時(shí)都會(huì)在getattr之前觸發(fā),觸發(fā)了getattribute就不會(huì)在觸發(fā)getattr了
class Base:
n = 0
class Point(Base):
z = 6
def __init__(self, x, y):
self.x = x
self.y = y
def show(self):
print(self.x, self.y)
def __getattr__(self, item):
return item
>>> p1.x
4
>>> p1.z
6
>>> p1.n
0
>>> p1.t
't'
實(shí)例屬性會(huì)按照繼承關(guān)系尋找,如果找不到,就會(huì)執(zhí)行__getattr__()
方法,如果沒(méi)有這個(gè)方法,就會(huì)拋出AttributeError
異常標(biāo)識(shí)找不到屬性。
__getattribute__(self, name)
定義當(dāng)該類的屬性被訪問(wèn)時(shí)的行為(先調(diào)用該方法,查看是否存在該屬性,若不存在,接著去調(diào)用__getattr__)
觸發(fā)時(shí)機(jī):使用對(duì)象成員時(shí)觸發(fā),無(wú)論成員是否存在
參數(shù):1個(gè)接收當(dāng)前對(duì)象self,一個(gè)是獲取的成員的名稱字符串
返回值:必須有
作用:在具有封裝操作(私有化時(shí)),為程序開(kāi)部分訪問(wèn)權(quán)限使用
class Base:
n = 0
class Point(Base):
z = 6
def __init__(self, x, y):
self.x = x
self.y = y
def __getattr__(self, item):
return item
def __getattribute__(self, item):
return item
>>> p1 = Point(4, 5)
>>> print(p1.__dict__)
__dict__
>>> print(p1.x)
x
>>> print(p1.z)
z
>>> print(p1.n)
n
>>> print(p1.t)
t
>>> print(Point.__dict__)
{'__module__': '__main__', 'z': 6, '__init__': <function Point.__init__ at 0x000001F5EB7063A8>, '__getattr__': <function Point.__getattr__ at 0x000001F5EB706558>, '__getattribute__': <function Point.__getattribute__ at 0x000001F5EB706168>, '__doc__': None}
>>> print(Point.z)
6
實(shí)例的所有的屬性訪問(wèn),第一個(gè)都會(huì)調(diào)用__getattribute__方法,它阻止了屬性的查找,該方法應(yīng)該返回值或者拋出一個(gè)AttributeError異常。
該方法的返回值將作為屬性查找的結(jié)果。
如果拋出AttributeError異常,則會(huì)直接調(diào)用__getattr__方法,因?yàn)閷傩詻](méi)有找到,__getattribute__方法中為了避免在該方法中無(wú)限遞歸,它的實(shí)現(xiàn)應(yīng)該永遠(yuǎn)調(diào)用基類的同名方法以訪問(wèn)需要的任何屬性。
需要注意的是,除非明確知道__getattrtbute__方法用來(lái)做什么,否則不要使用。
?
__setattr__(self, name, value)
定義當(dāng)一個(gè)屬性被設(shè)置時(shí)的行為
觸發(fā)時(shí)機(jī):設(shè)置對(duì)象成員值的時(shí)候觸發(fā)
參數(shù):1個(gè)當(dāng)前對(duì)象的self,一個(gè)是要設(shè)置的成員名稱字符串,一個(gè)是要設(shè)置的值
返回值:無(wú) 過(guò)程操作
作用:接管設(shè)置操作,可以在設(shè)置前之前進(jìn)行判斷驗(yàn)證等行為
注意:在當(dāng)前方法中無(wú)法使用成員=值的方式直接設(shè)置成員,否則會(huì)無(wú)限遞歸,必須借助object的設(shè)置方法來(lái)完成
class Base:
n = 0
class Point(Base):
z = 6
def __init__(self, x, y):
self.x = x
self.y = y
def show(self):
print(self.x, self.y)
def __getattr__(self, item):
return item
def __setattr__(self, key, value):
print(key, value)
# --------------------------------------------------
>>> p1 = Point(4, 5)
x 4
y 5
>>> print(p1.x)
x
>>> print(p1.z)
6
>>> print(p1.n)
0
>>> print(p1.t)
t
# --------------------------------------------------
>>> p1.x = 50
>>> print(p1.x)
x
>>> print(p1.__dict__)
{}
>>> p1.__dict__['x'] = 60
>>> print(p1.__dict__)
{'x': 60}
>>> p1.x
60
__delattr__(self, name)
定義當(dāng)一個(gè)屬性被刪除時(shí)的行為
觸發(fā)時(shí)機(jī):刪除對(duì)象成員時(shí)觸發(fā)
參數(shù):一個(gè)當(dāng)前對(duì)象的self
返回值:無(wú)
作用:可以在刪除成員時(shí)進(jìn)行驗(yàn)證。
__dir__(self)
觸發(fā)時(shí)機(jī):dir(對(duì)象)的時(shí)候觸發(fā)
參數(shù):1個(gè)接收當(dāng)前對(duì)象self
返回值:必須為序列類型(列表,元組,集合等,)
作用:可以自定義成員列表的返回值
例子
class C:
def __getattribute__(self, item):
print('__getattribute__')
return super().__getattribute__(item)
def __getattr__(self, item):
print('__getattr__')
def __setattr__(self, key, value):
print('__setattr__')
super().__setattr__(key, value)
def __delattr__(self, item):
print('__delattr__')
super().__delattr__(item)
c = C()
print('1-----')
c.x
# __getattribute__
# __getattr__
print('2-----')
c.x = 1
# __setattr__
print('3-----')
del c.x
# __delattr__
類型轉(zhuǎn)換魔術(shù)方法
- __complex__ (self)定義當(dāng)被 complex() 調(diào)用時(shí)的行為(需要返回恰當(dāng)?shù)闹担?/li>
- __int__(self) 定義當(dāng)被 int() 調(diào)用時(shí)的行為(需要返回恰當(dāng)?shù)闹担?/li>
- __float__(self) 定義當(dāng)被 float() 調(diào)用時(shí)的行為(需要返回恰當(dāng)?shù)闹担?/li>
- __round__(self[, n]) 定義當(dāng)被 round() 調(diào)用時(shí)的行為(需要返回恰當(dāng)?shù)闹担?/li>
- __index(self)__ 1. 當(dāng)對(duì)象是被應(yīng)用在切片表達(dá)式中時(shí),實(shí)現(xiàn)整形強(qiáng)制轉(zhuǎn)換
- 2. 如果你定義了一個(gè)可能在切片時(shí)用到的定制的數(shù)值型,你應(yīng)該定義 index
- 3. 如果 index 被定義,則 int 也需要被定義,且返回相同的值
上下文相關(guān)的魔術(shù)方法
__enter__(self)
1. 定義當(dāng)使用 with 語(yǔ)句時(shí)的初始化行為
2. enter 的返回值被 with 語(yǔ)句的目標(biāo)或者 as 后的名字綁定
__exit__(self, exctype, excvalue, traceback)
1. 定義當(dāng)一個(gè)代碼塊被執(zhí)行或者終止后上下文管理器應(yīng)該做什么
2. 一般被用來(lái)處理異常,清除工作或者做一些代碼塊執(zhí)行完畢之后的日常工作
# __enter__和__exit__示例
class DatabaseConnection:
def __init__(self, db_url):
self.db_url = db_url
def __enter__(self):
self.connection = open(self.db_url)
return self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
self.connection.close()
# 使用 with 語(yǔ)句打開(kāi)數(shù)據(jù)庫(kù)連接,并在結(jié)束時(shí)自動(dòng)關(guān)閉連接
with DatabaseConnection('example.db') as conn:
# 執(zhí)行一些操作
cursor = conn.cursor()
cursor.execute('SELECT * FROM users')
rows = cursor.fetchall()
print(rows)
容器相關(guān)的魔術(shù)方法
- __len__(self) 定義當(dāng)被 len() 調(diào)用時(shí)的行為(返回容器中元素的個(gè)數(shù))
- __getitem__(self, key) 定義獲取容器中指定元素的行為,相當(dāng)于 self[key]
- __setitem__(self, key, value) 定義設(shè)置容器中指定元素的行為,相當(dāng)于 self[key] = value
- __delitem__(self, key) 定義刪除容器中指定元素的行為,相當(dāng)于 del self[key]
- __iter__(self) 定義當(dāng)?shù)萜髦械脑氐男袨?/li>
- __next__(self)從iterable對(duì)象中獲取下一個(gè)元素
- __reversed__(self) 定義當(dāng)被 reversed() 調(diào)用時(shí)的行為
- __contains__(self, item) 定義當(dāng)使用成員測(cè)試運(yùn)算符(in 或 not in)時(shí)的行為
- __missing__字典使用__getitem__()調(diào)用時(shí),key不存在執(zhí)行該方法
# __getitem__和__setitem__示例
class MyList:
def __init__(self, items):
self.items = items
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
l = MyList([1, 2, 3, 4])
print(l[2]) # 輸出: 3
l[2] = 5
print(l[2]) # 輸出: 5
# __contains__示例
class MyList:
def __init__(self, items):
self.items = items
def __contains__(self, item):
return item in self.items
l = MyList([1, 2, 3, 4])
print(2 in l) # 輸出: True
print(5 in l) # 輸出: False
# __iter__和__next__示例
class MyRange:
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start >= self.end:
raise StopIteration
value = self.start
self.start += 1
return value
r = MyRange(0, 5)
for i in r:
print(i) # 輸出: 0 1 2 3 4
?魔法屬性
__doc__
這是一個(gè)屬性,獲取類或?qū)ο髢?nèi)部文檔。
class MyClass():
"""
我是一個(gè)類,這里說(shuō)明一些有用的信息
"""
def __init__(self):
pass
print(MyClass.__doc__)
# 我是一個(gè)類,這里說(shuō)明一些有用的信息
__name__
這也是一個(gè)屬性,獲取類名或函數(shù)名?
class Class1:
pass
class MyClass:
def task1(self, func1):
print(func1.__name__)
def func():
print("我是func1函數(shù)")
>>> obj = MyClass()
>>> obj.task1(func)
func
>>> obj.task1(Class1)
Class1
__class__
獲取當(dāng)前對(duì)象獲取的類
class Class1:
pass
>>> obj = Class1()
>>> print(obj.__class__)
<class '__main__.Class1'>
>>> print(obj.__class__.__name__)
Class1
__base__
獲取一個(gè)類直接繼承的所有父類,返回元組。
class Class1:
pass
class Class2:
pass
class MyClass(Class1, Class2):
pass
>>> print(MyClass.__bases__)
(<class '__main__.Class1'>, <class '__main__.Class2'>)
__dict__
獲取類或?qū)ο蟮牡?strong>內(nèi)部成員結(jié)構(gòu)。主要用來(lái)獲取用戶自定義的屬性,以及這個(gè)屬性對(duì)應(yīng)的值。返回的是一個(gè)字典。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-686392.html
class MyClass():
name1 = "Lsir"
name2 = "Wsir"
name3 = "Zsir"
def task1(self):
print("task1")
def task2(self):
print("tesk2")
def task3(self):
print("task3")
>>> print(MyClass.__dict__)
{'__module__': '__main__', 'name1': 'Lsir', 'name2': 'Wsir', 'name3': 'Zsir', 'task1': <function MyClass.task1 at 0x0000020C16385558>, 'task2': <function MyClass.task2 at 0x0000020C16385D38>, 'task3': <function MyClass.task3 at 0x0000020C16385708>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}
和dir
函數(shù)做一個(gè)區(qū)分。dir
函數(shù)返回的是這個(gè)對(duì)象上擁有的所有屬性,包括Python內(nèi)置的屬性和用戶自己添加的,并且只是獲取屬性名字,不會(huì)獲取這個(gè)屬性對(duì)應(yīng)的值。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-686392.html
到了這里,關(guān)于Python魔術(shù)方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!