在Python中,類(lèi)特殊成員是指以雙下劃線開(kāi)頭和結(jié)尾的屬性和方法,也被稱(chēng)為魔術(shù)方法(Magic methods)或特殊方法(Special methods)。這些特殊成員在類(lèi)的定義中具有特殊的語(yǔ)法和功能,用于實(shí)現(xiàn)對(duì)象的特定行為和操作。
特殊方法一般由Python解釋器調(diào)用,無(wú)需手動(dòng)調(diào)用。通過(guò)在類(lèi)中定義這些特殊方法,可以改變對(duì)象的默認(rèn)行為,使其具備更多的功能和操作。特殊方法提供了一種更加Pythonic的面向?qū)ο缶幊痰姆绞剑梢宰尨a更加簡(jiǎn)潔和易讀。
__init__
__init__
是Python中的一個(gè)特殊方法,也被稱(chēng)為構(gòu)造方法。它在創(chuàng)建對(duì)象時(shí)自動(dòng)調(diào)用,用于初始化對(duì)象的屬性。通過(guò)在類(lèi)中定義 __init__
方法,我們可以在對(duì)象創(chuàng)建時(shí)為其賦予初始狀態(tài),設(shè)置屬性的默認(rèn)值,或執(zhí)行其他必要的初始化操作。
__init__
方法的格式通常如下:
def __init__(self, arg1, arg2, ...):
self.attribute1 = arg1
self.attribute2 = arg2
# ...
self
代表對(duì)象本身,arg1
、arg2
等是用于接收傳入的參數(shù)的形參,我們可以根據(jù)實(shí)際需要為 __init__
方法傳入不同的參數(shù)。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person1 = Person("Alittle", 30)
在 __init__
方法中,我們可以執(zhí)行其他的初始化操作,例如連接數(shù)據(jù)庫(kù)、打開(kāi)文件、設(shè)置默認(rèn)值等。這使得我們能夠在創(chuàng)建對(duì)象時(shí),做一些必要的準(zhǔn)備工作,確保對(duì)象在初始化后即可用。
需要注意的是,Python 中的 __init__
方法是可選的,不是必須定義的。如果類(lèi)中沒(méi)有定義 __init__
方法,Python 會(huì)使用默認(rèn)的空的 __init__
方法。但通常情況下,我們會(huì)定義 __init__
方法來(lái)初始化對(duì)象的屬性。
__del__
__del__
是Python中的一個(gè)特殊方法,也被稱(chēng)為析構(gòu)方法。它在對(duì)象被銷(xiāo)毀前自動(dòng)調(diào)用,用于進(jìn)行清理工作。當(dāng)對(duì)象的引用計(jì)數(shù)為零時(shí)(即沒(méi)有任何變量引用該對(duì)象),Python解釋器會(huì)自動(dòng)觸發(fā) __del__
方法的調(diào)用。
__del__
方法的格式通常如下:
def __del__(self):
# 清理代碼
在 __del__
方法中,self
代表對(duì)象本身。我們可以在 __del__
方法中編寫(xiě)需要在對(duì)象銷(xiāo)毀之前執(zhí)行的清理代碼,例如關(guān)閉文件、釋放資源、記錄日志等。
class FileHandler:
def __init__(self, filename):
self.file = open(filename, 'w')
def write_data(self, data):
self.file.write(data)
def __del__(self):
self.file.close()
handler = FileHandler("data.txt")
handler.write_data("Hello, World!")
# 在退出程序或手動(dòng)執(zhí)行 del handler 時(shí),會(huì)自動(dòng)調(diào)用 __del__ 方法關(guān)閉文件
我們定義了一個(gè) FileHandler
類(lèi),其中的 __init__
方法用于打開(kāi)文件并創(chuàng)建一個(gè) file
對(duì)象。write_data
方法用于向文件寫(xiě)入數(shù)據(jù)。在 __del__
方法中,我們通過(guò) self.file.close()
關(guān)閉了文件。當(dāng)程序退出或手動(dòng)執(zhí)行 del handler
時(shí),對(duì)象 handler
被銷(xiāo)毀,會(huì)自動(dòng)調(diào)用 __del__
方法關(guān)閉文件,確保資源的正常釋放。
另外需要注意的是,__del__
方法的調(diào)用是由Python解釋器自動(dòng)控制的,并不是我們手動(dòng)調(diào)用的。因此,我們不能依賴(lài) __del__
方法來(lái)進(jìn)行關(guān)鍵性的清理工作,如釋放內(nèi)存。一般來(lái)說(shuō),Python有自己的垃圾回收機(jī)制,會(huì)自動(dòng)管理對(duì)象的內(nèi)存釋放。我們只需確保在 __del__
方法中執(zhí)行一些簡(jiǎn)單的清理操作即可。此外,應(yīng)盡量避免在 __del__
方法中拋出異常,以免影響其他代碼的執(zhí)行。
__str__
__str__
也是Python中的一個(gè)特殊方法,也被稱(chēng)為字符串表示方法。它定義了當(dāng)我們對(duì)一個(gè)對(duì)象使用內(nèi)置的 str()
函數(shù)或 print()
函數(shù)進(jìn)行輸出時(shí),應(yīng)該返回的字符串形式表示。簡(jiǎn)而言之,__str__
方法用于定制對(duì)象的字符串輸出。
__str__
方法的格式通常如下:
def __str__(self):
# 返回表示對(duì)象的字符串
在 __str__
方法中,self
代表對(duì)象本身,沒(méi)有其他的參數(shù)了,我們可以在該方法中編寫(xiě)需要返回的表示對(duì)象的字符串形式的代碼,例如組織對(duì)象的屬性信息、狀態(tài)等。
以下是一個(gè)示例,展示了如何使用 __str__
方法來(lái)定制對(duì)象的字符串輸出:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
print("call __str__")
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(p)
print("-----------------")
str(p)
上面的示例中的輸出
call __str__
Point(3, 4)
-----------------
call __str__
我們定義了一個(gè) Point
類(lèi),其中的 __init__
方法用于初始化點(diǎn)的坐標(biāo)。在 __str__
方法中,我們使用格式化字符串 f-string 將點(diǎn)的坐標(biāo)表示為 '(x, y)' 的形式。當(dāng)我們對(duì) p
對(duì)象使用 print(p)
和 str(p)
時(shí),會(huì)自動(dòng)調(diào)用 __str__
方法,并返回該方法中定義的字符串 (3, 4)
。
__repr__
__repr__
與 __str__
方法類(lèi)似,下面直接用一個(gè)例子來(lái)說(shuō)明這個(gè)和 __str__
的區(qū)別。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
print("call __str__")
return f"Point1({self.x}, {self.y})"
def __repr__(self):
print("call __repr__")
return f"Point2({self.x}, {self.y})"
p = Point(3, 4)
print(p)
print("-----------------")
str(p)
repr(p)
上面的示例中的輸出
call __str__
Point1(3, 4)
-----------------
call __str__
call __repr__
從上面的輸出可以看出,repr(p)
函數(shù)可以自動(dòng)調(diào)用 __repr__
,默認(rèn)情況下,__str__
和 __repr__
同時(shí)存在的話,str()
和 print()
函數(shù)就會(huì)優(yōu)先調(diào)用 __str__
,而如果只有 __repr__
的話,就會(huì)調(diào)用 __repr__
,不信你們可以把上面例子中的 __str__
注釋掉,然后看看輸出情況。
__len__
__len__
用于定義對(duì)象的長(zhǎng)度。它主要被用于內(nèi)置函數(shù) len()
的操作,用于返回一個(gè)對(duì)象的長(zhǎng)度或元素的個(gè)數(shù)。
__len__
方法的格式通常如下:
def __len__(self):
# 返回對(duì)象的長(zhǎng)度或元素的個(gè)數(shù)
在 __len__
方法中,self
代表對(duì)象本身。我們可以在該方法中編寫(xiě)代碼,返回一個(gè)整數(shù),表示對(duì)象的長(zhǎng)度或元素的個(gè)數(shù)。
以下是一個(gè)示例,展示了如何使用 __len__
方法來(lái)定義一個(gè)自定義的容器類(lèi)并使用 len()
函數(shù)獲取其長(zhǎng)度:
class MyContainer:
def __init__(self):
self.data = []
def __len__(self):
return len(self.data)
def add(self, element):
self.data.append(element)
container = MyContainer()
container.add(1)
container.add(2)
container.add(3)
print(len(container)) # 輸出 3,調(diào)用了 __len__ 方法
在上面的示例中,我們定義了一個(gè)名為 MyContainer
的容器類(lèi),該類(lèi)包含一個(gè)名為 data
的列表用于存儲(chǔ)元素。在 __len__
方法中,我們使用內(nèi)置函數(shù) len()
計(jì)算了 data
列表的長(zhǎng)度,并返回該長(zhǎng)度。當(dāng)我們通過(guò)調(diào)用 len(container)
來(lái)獲取 container
對(duì)象的長(zhǎng)度時(shí),實(shí)際上會(huì)自動(dòng)調(diào)用 __len__
方法,并返回該方法中定義的長(zhǎng)度值。
__len__
方法應(yīng)該返回一個(gè)整數(shù),表示對(duì)象的長(zhǎng)度或元素的個(gè)數(shù)。如果一個(gè)類(lèi)沒(méi)有定義 __len__
方法,或者 __len__
方法返回的值不是整數(shù)類(lèi)型,那么調(diào)用 len()
函數(shù)時(shí)會(huì)拋出 TypeError
異常。
__getitem__和__setitem__
__getitem__
和 __setitem__
幾乎都是成對(duì)出現(xiàn)的,__getitem__
用于定義對(duì)象的索引操作,即允許通過(guò)索引值訪問(wèn)對(duì)象的元素,__setitem__
用于定義對(duì)象的賦值操作,即允許通過(guò)索引值設(shè)置對(duì)象的元素值,它主要用于支持下標(biāo)操作和切片操作。
__getitem__
和 __setitem__
方法的格式通常如下:
def __getitem__(self, index):
# 返回指定索引位置的元素
def __setitem__(self, index, value):
# 設(shè)置指定索引位置的元素為指定的值
這兩個(gè)方法一個(gè)就是取值,一個(gè)就是賦值,主要就是應(yīng)用在對(duì)象上面,相對(duì)而言比較好理解。
class MyList:
def __init__(self):
self.data = []
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
mylist = MyList()
mylist.data = [1, 2, 3, 4, 5]
print(mylist[2]) # 輸出 3,調(diào)用了 __getitem__ 方法
mylist[2] = 10 # 調(diào)用了 __setitem__ 方法賦值
print(mylist[2]) # 輸出 10,調(diào)用了 __getitem__ 方法
在上面的示例中,我們定義了一個(gè)名為 MyList
的列表類(lèi),該類(lèi)包含一個(gè)名為 data
的列表用于存儲(chǔ)元素。通過(guò)實(shí)現(xiàn) __getitem__
和 __setitem__
方法,我們可以使用類(lèi)似于列表的方式通過(guò)索引來(lái)訪問(wèn)和設(shè)置 data
列表中的元素。__getitem__
方法通常與 __setitem__
方法一起使用,以支持對(duì)象的索引和切片操作。通過(guò)定義這些方法,我們可以使自定義的類(lèi)對(duì)象能夠像內(nèi)置的容器類(lèi)型一樣進(jìn)行元素的訪問(wèn)和修改。
如果一個(gè)類(lèi)沒(méi)有定義 __getitem__
和 __setitem__
方法,或者__getitem__
和 __setitem__
方法不能處理給定的索引值或切片對(duì)象,那么當(dāng)我們嘗試通過(guò)索引或切片來(lái)訪問(wèn)(設(shè)置)對(duì)象時(shí),會(huì)拋出 TypeError
異常。
__call__
__call__
用于使對(duì)象能夠像函數(shù)一樣被調(diào)用。通過(guò)定義 __call__
方法,我們可以將一個(gè)對(duì)象變成一個(gè)可調(diào)用的實(shí)例,類(lèi)似于函數(shù)的行為。
__call__
方法的格式通常如下:
def __call__(self, *args, **kwargs):
# 定義對(duì)象的調(diào)用邏輯
在 __call__
方法中,self
代表對(duì)象本身,args
和 kwargs
是傳遞給對(duì)象調(diào)用時(shí)的參數(shù)。
當(dāng)我們像調(diào)函數(shù)一樣使用對(duì)象時(shí),Python 解釋會(huì)自動(dòng)調(diào)用對(duì)象的 __call__
方法,并將傳入的參數(shù)作為參數(shù)遞給該方法。我們可以在 __call__
方法中定義對(duì)象的調(diào)用邏,然后執(zhí)行相應(yīng)的操作。
以下一個(gè)示例,展示了如何使用 __call__
方法來(lái)定義一個(gè)可調(diào)用的對(duì)象:
class Adder:
def __call__(self, x, y):
return x + y
add = Adder()
# 將對(duì)象 add 當(dāng)作函數(shù)進(jìn)行調(diào)用
result = add(3, 5)
print(result) # 輸出:8
在上述示例中,我們定義了一個(gè) Adder
類(lèi),并實(shí)現(xiàn)了 __call__
方法。在該方法中,我們將傳入的兩個(gè)參數(shù)進(jìn)行相加,Python 解釋器會(huì)自動(dòng)調(diào)用對(duì)象 add
的 __call__
方法,并將傳遞給該方法。__call__
方法中的邏輯會(huì)被執(zhí)行,參數(shù)進(jìn)行相加操作,然后返回結(jié)果。
通過(guò)使用 __call__
方法,我們可以將一個(gè)對(duì)象實(shí)例化后,即可像函數(shù)一樣進(jìn)行調(diào)用,并執(zhí)行預(yù)定義的邏輯。這樣可以增加對(duì)象的靈活性,使其更加接近函數(shù)的行為。__call__
方法只有在對(duì)象被調(diào)用時(shí)才會(huì)被調(diào)用,也就是對(duì)象被函數(shù)那樣調(diào)用。
通常情況下,__call__
方法常用于實(shí)現(xiàn)可調(diào)用的對(duì)象,如自定義的函數(shù)對(duì)象、裝飾器、上下文管理器等。通過(guò)定義 __call__
方法,我們可以使對(duì)象具有函數(shù)的特性,并能夠直接調(diào)用執(zhí)行相應(yīng)的邏輯。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-786457.html
更多精彩內(nèi)容,請(qǐng)關(guān)注同名公眾:一點(diǎn)sir(alittle-sir)
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-786457.html
到了這里,關(guān)于Python教程(23)——Python類(lèi)中常用的特殊成員的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!