Python利用魔法方法玩轉(zhuǎn)對象
Python中魔法方法(magic method)其實就是那些被雙下劃線包圍的方法,比如__init__
,__str__
等等。
這些魔法方法為類添加了**“魔力”,讓我們可以在面向?qū)ο缶幊讨杏酶雍啙嵉拇a來操作對象。
本篇根據(jù)面向?qū)ο缶幊痰囊恍﹫鼍皝斫榻B常用的魔法方法**。
1. 對象構(gòu)建
為了初始化對象,我們常常在對象中定義一個__init__
方法,比如:
class Student(object): """ 學(xué)生信息 """ def __init__(self, name): print("[__init__] Student 初始化...") self.name = name # 創(chuàng)建對象 stu = Student("小明") # 運行結(jié)果 [__init__] Student 初始化...
當(dāng)我們創(chuàng)建對象時,會自動調(diào)用魔法方法__init__
去初始化屬性。
與__init__
對應(yīng)的是__del__
,它會在對象失效的調(diào)用,我們可以在__del__
方法中清理對象Student
占用的資源。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name def __del__(self): print("[__del__] 清理 Student...") def foo(): print("進(jìn)入 foo 函數(shù)...") stu = Student("小明") print("離開 foo 函數(shù)...") foo() # 運行結(jié)果 進(jìn)入 foo 函數(shù)... [__init__] 初始化 Student... 離開 foo 函數(shù)... [__del__] 清理 Student...
進(jìn)入 foo
函數(shù)后創(chuàng)建對象,離開后,自動清理對象。
2. 對象屬性訪問
python
的對象是可以直接訪問屬性的,但是訪問不存在的屬性時,會拋出異常。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name stu = Student("小明") print(stu.name) print(stu.fullname) # 運行結(jié)果 [__init__] 初始化 Student... 小明 AttributeError: 'Student' object has no attribute 'fullname'
如果不想拋出異常,從而影響程序的其他部分的運行,這里可以用魔法方法 __getattr__
來控制訪問了不存在的屬性時的行為。
比如,下面的示例中,訪問不存在的屬性時,返回False
,不拋出異常。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name def __getattr__(self, attr): print("[__getattr__] 訪問了 Student 不存在的屬性 {}".format(attr)) return False stu = Student("小明") print(stu.name) print(stu.fullname) # 運行結(jié)果 [__init__] 初始化 Student... 小明 [__getattr__] 訪問了 Student 不存在的屬性 fullname False
與__getattr__
相對的另一個魔法方法__setattr__
,與__getattr__
不同的是,它既可以設(shè)置不存在的屬性,也可以設(shè)置已存在的屬性。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name def __setattr__(self, attr, value): print("[__setattr__] 設(shè)置 Student 屬性 {}={}".format(attr, value)) self.__dict__[attr] = value stu = Student("小明") print(stu.name) # 已存在的屬性 stu.name = "小華" print(stu.name) # 不存在的屬性 stu.fullname = "小紅" print(stu.fullname) # 運行結(jié)果 [__init__] 初始化 Student... [__setattr__] 設(shè)置 Student 屬性 name=小明 小明 [__setattr__] 設(shè)置 Student 屬性 name=小華 小華 [__setattr__] 設(shè)置 Student 屬性 fullname=小紅 小紅
每次對屬性賦值,都會觸發(fā)__setattr__
方法,即使在__init__
中給self.name
賦值,也觸發(fā)了__setattr__
方法,所以一共被觸發(fā)了三次。
3. 對象比較
在使用基本類型(比如數(shù)值類型,字符串類型等)的時候,比較其大小非常簡單。
print(1 < 2) print(1 > 2) print("abc" < "edf") # 運行結(jié)果 True False True
而對象直接互相比較大小則沒有這么簡單了,還是用上面的Student類,這次我們加上各門功課的分?jǐn)?shù)。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics stu1 = Student("小明", 80, 90, 75) stu2 = Student("小紅", 85, 70, 95) # 比較兩個學(xué)生對象 print(stu1 > stu2) # 運行結(jié)果 TypeError: '>' not supported between instances of 'Student' and 'Student'
不出所料,拋出了異常。
其實我們比較兩個學(xué)生對象,是想要比較兩個學(xué)生的總分誰高誰低。
這時,我們就可以實現(xiàn)用于比較的魔法方法,比如 __eq__
,__lt__
,__gt__
等等。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics def total(self): return self.chinese + self.english + self.mathematics def __eq__(self, other: Student): return self.total() == other.total() def __lt__(self, other: Student): return self.total() < other.total() def __gt__(self, other: Student): return self.total() > other.total() stu1 = Student("小明", 80, 90, 75) stu2 = Student("小紅", 85, 70, 95) print(stu1 > stu2) print(stu1 == stu2) print(stu1 < stu2) # 運行結(jié)果 False False True
實現(xiàn)相應(yīng)的魔法方法,就能使用相應(yīng)的比較運算符來直接比較對象了。
PS. 上面的例子中只實現(xiàn)了大于(__gt__
),等于(__eq__
),小于(__lt__
)的比較,還有其他魔法方法,比如:大于等于(__ge__
),不等于(__ne__
),小于等于(__le__
)等等。
實現(xiàn)的方式和上面例子中類似。
4. 對象輸出
對于一個基本類型的變量,顯示其內(nèi)容非常簡單,而對于一個對象,顯示的內(nèi)容可能就不是我們所期望的了。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics s = "hello world" print(s) stu = Student("小明", 80, 90, 75) print(stu) # 運行結(jié)果 hello world <__main__.Student object at 0x00000164F72FD6D0>
字符串內(nèi)容可以直接顯示出來,而對象stu
只是顯示了它的內(nèi)存地址,對我們了解其中的內(nèi)容毫無幫助。
此時,就可以拿出我們的魔法方法__str__
,來定制對象在print
時顯示的內(nèi)容。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics def __str__(self): return """姓名: {} 成績: 1. 語文: {} 分 2. 數(shù)學(xué): {} 分 3. 英語: {} 分""".format( self.name, self.chinese, self.mathematics, self.english, ) stu = Student("小明", 80, 90, 75) print(stu) # 運行結(jié)果 姓名: 小明 成績: 1. 語文: 80 分 2. 數(shù)學(xué): 75 分 3. 英語: 90 分
通過魔法方法__str__
,可以讓對象按照我們希望的形式顯示出來。
5. 對象運算
對象除了可以像普通變量一樣比較,輸出,是不是也可以像變量一樣進(jìn)行算術(shù)運算呢?
比如:
class Student(object): def __init__(self, name, scores): self.name = name self.scores = scores def __str__(self): return """姓名: {}, 各科成績: {}""".format( self.name, self.scores, ) stu1 = Student("小明", [80, 90, 75]) stu2 = Student("小紅", [85, 70, 95]) print(stu1) print(stu2) print(stu1 + stu2) # 運行結(jié)果 姓名: 小明, 各科成績: [80, 90, 75] 姓名: 小紅, 各科成績: [85, 70, 95] TypeError: unsupported operand type(s) for +: 'Student' and 'Student'
果然,直接進(jìn)行算術(shù)運算是不行的。
還是得借助魔法方法,下面在類中實現(xiàn)加法和減法的魔法方法。
class Student(object): def __init__(self, name, scores): self.name = name self.scores = scores def __str__(self): return """姓名: {}, 各科成績: {}""".format( self.name, self.scores, ) def __add__(self, other: Student): name = "{}, {} 成績合計".format(self.name, other.name) scores = [self.scores[i] + other.scores[i] for i in range(len(self.scores))] return Student(name, scores) def __sub__(self, other: Student): name = "{}, {} 成績之差".format(self.name, other.name) scores = [self.scores[i] - other.scores[i] for i in range(len(self.scores))] return Student(name, scores) stu1 = Student("小明", [80, 90, 75]) stu2 = Student("小紅", [85, 70, 95]) print(stu1) print(stu2) print(stu1 + stu2) print(stu1 - stu2) # 運行結(jié)果 姓名: 小明, 各科成績: [80, 90, 75] 姓名: 小紅, 各科成績: [85, 70, 95] 姓名: 小明, 小紅 成績合計, 各科成績: [165, 160, 170] 姓名: 小明, 小紅 成績之差, 各科成績: [-5, 20, -20]
其他的算術(shù)運算(比如,乘法,除法和求模等等)也有相應(yīng)的魔法方法,仿照上面的示例實現(xiàn)即可。
6. 總結(jié)
Python
的魔法方法很多,本文只是列舉了其中很少的一部分,github
上有一個示例python
文件,列舉了很多魔法方法,供參考:magicmethods.py
到此這篇關(guān)于Python利用魔法方法玩轉(zhuǎn)對象的文章就介紹到這了,更多相關(guān)Python魔法方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在django view中給form傳入?yún)?shù)的例子
今天小編就為大家分享一篇在django view中給form傳入?yún)?shù)的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07python互斥鎖、加鎖、同步機制、異步通信知識總結(jié)
本篇文章給大家詳細(xì)講述了python互斥鎖、加鎖、同步機制、異步通信相關(guān)知識點,對此有興趣的朋友收藏下。2018-02-02Pytorch - TORCH.NN.INIT 參數(shù)初始化的操作
這篇文章主要介紹了Pytorch - TORCH.NN.INIT 參數(shù)初始化的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02