Python 特殊成员和魔法方法
Python中有大量類似__doc__這種以雙下劃線開頭和結尾的特殊成員及“魔法方法”,它們有著非常重要的地位和作用,也是Python語言獨具特色的語法之一!
比如:
- __init__ : 構造函數,在生成對象時調用
- __del__ : 析構函數,釋放對象時使用
- __repr__ : 打印,轉換
- __setitem__ : 按照索引賦值
- __getitem__: 按照索引獲取值
- __len__: 獲得長度
- __cmp__: 比較運算
- __call__: 調用
- __add__: 加運算
- __sub__: 減運算
- __mul__: 乘運算
- __div__: 除運算
- __mod__: 求余運算
- __pow__: 冪
需要注意的是,這些成員里面有些是方法,調用時要加括號,有些是屬性,調用時不需要加括號(廢話!)。下面將一些常用的介紹一下,:
1. __doc__
說明性文檔和信息。Python自建,無需自定義。
class Foo:""" 描述類信息,可被自動收集 """def func(self):pass# 打印類的說明文檔 print(Foo.__doc__)2. __init__()
實例化方法,通過類創建實例時,自動觸發執行。
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Foo:def __init__(self, name):self.name = nameself.age = 18obj = Foo(jack') # 自動執行類中的 __init__ 方法3.__module__和__class__
__module__ 表示當前操作的對象在屬于哪個模塊。
__class__表示當前操作的對象屬于哪個類。
這兩者也是Python內建,無需自定義。
class Foo:passobj = Foo() print(obj.__module__) print(obj.__class__)------------ 運行結果: __main__ <class '__main__.Foo'>4. __del__()
析構方法,當對象在內存中被釋放時,自動觸發此方法。
注:此方法一般無須自定義,因為Python自帶內存分配和釋放機制,除非你需要在釋放的時候指定做一些動作。析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Foo:def __del__(self):print("我被回收了!")obj = Foo()del obj5.__call__()
如果為一個類編寫了該方法,那么在該類的實例后面加括號,可會調用這個方法。
注:構造方法的執行是由類加括號執行的,即:對象 = 類名(),而對于__call__() 方法,是由對象后加括號觸發的,即:對象() 或者 類()()
class Foo:def __init__(self):passdef __call__(self, *args, **kwargs):print('__call__')obj = Foo() # 執行 __init__ obj() # 執行 __call__那么,怎么判斷一個對象是否可以被執行呢?能被執行的對象就是一個Callable對象,可以用Python內建的callable()函數進行測試,我們在前面的章節已經介紹過這個函數了。
>>> callable(Student()) True >>> callable(max) True >>> callable([1, 2, 3]) False >>> callable(None) False >>> callable('str') False >>> callable(int) True >>> callable(str) True6. __dict__
列出類或對象中的所有成員!非常重要和有用的一個屬性,Python自建,無需用戶自己定義。
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Province:country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):print('func')# 獲取類的成員 print(Province.__dict__)# 獲取 對象obj1 的成員 obj1 = Province('HeBei',10000) print(obj1.__dict__)# 獲取 對象obj2 的成員 obj2 = Province('HeNan', 3888) print(obj2.__dict__)7. __str__()
如果一個類中定義了__str__()方法,那么在打印對象時,默認輸出該方法的返回值。這也是一個非常重要的方法,需要用戶自己定義。
下面的類,沒有定義__str__()方法,打印結果是:<__main__.Foo object at 0x000000000210A358>
class Foo:passobj = Foo() print(obj)定義了__str__()方法后,打印結果是:‘jack’。
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Foo:def __str__(self):return 'jack'obj = Foo() print(obj)8、__getitem__()、__setitem__()、__delitem__()
取值、賦值、刪除這“三劍客”的套路,在Python中,我們已經見過很多次了,比如前面的@property裝飾器。
Python中,標識符后面加圓括號,通常代表執行或調用方法的意思。而在標識符后面加中括號[],通常代表取值的意思。Python設計了__getitem__()、__setitem__()、__delitem__()這三個特殊成員,用于執行與中括號有關的動作。它們分別表示取值、賦值、刪除數據。
也就是如下的操作:
a = 標識符[] : 執行__getitem__方法 標識符[] = a : 執行__setitem__方法 del 標識符[] : 執行__delitem__方法如果有一個類同時定義了這三個魔法方法,那么這個類的實例的行為看起來就像一個字典一樣,如下例所示:
class Foo:def __getitem__(self, key):print('__getitem__',key)def __setitem__(self, key, value):print('__setitem__',key,value)def __delitem__(self, key):print('__delitem__',key)obj = Foo()result = obj['k1'] # 自動觸發執行 __getitem__ obj['k2'] = 'jack' # 自動觸發執行 __setitem__ del obj['k1'] # 自動觸發執行 __delitem__9. __iter__()
這是迭代器方法!列表、字典、元組之所以可以進行for循環,是因為其內部定義了 iter()這個方法。如果用戶想讓自定義的類的對象可以被迭代,那么就需要在類中定義這個方法,并且讓該方法的返回值是一個可迭代的對象。當在代碼中利用for循環遍歷對象時,就會調用類的這個__iter__()方法。
普通的類:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Foo:passobj = Foo()for i in obj:print(i)# 報錯:TypeError: 'Foo' object is not iterable<br># 原因是Foo對象不可迭代添加一個__iter__(),但什么都不返回:
class Foo:def __iter__(self):passobj = Foo()for i in obj:print(i)# 報錯:TypeError: iter() returned non-iterator of type 'NoneType'#原因是 __iter__方法沒有返回一個可迭代的對象返回一個個迭代對象:
class Foo:def __init__(self, sq):self.sq = sqdef __iter__(self):return iter(self.sq)obj = Foo([11,22,33,44])for i in obj:print(i)# 這下沒問題了!最好的方法是使用生成器:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Foo:def __init__(self):passdef __iter__(self):yield 1yield 2yield 3obj = Foo() for i in obj:print(i)10、__len__()
在Python中,如果你調用內置的len()函數試圖獲取一個對象的長度,在后臺,其實是去調用該對象的__len__()方法,所以,下面的代碼是等價的:
>>> len('ABC') 3 >>> 'ABC'.__len__() 3Python的list、dict、str等內置數據類型都實現了該方法,但是你自定義的類要實現len方法需要好好設計。
11. __repr__()
這個方法的作用和__str__()很像,兩者的區別是__str__()返回用戶看到的字符串,而__repr__()返回程序開發者看到的字符串,也就是說,__repr__()是為調試服務的。通常兩者代碼一樣。
class Foo:def __init__(self, name):self.name = namedef __str__(self):return "this is %s" % self.name__repr__ = __str__12. __add__: 加運算 __sub__: 減運算 __mul__: 乘運算 __div__: 除運算__mod__: 求余運算 __pow__: 冪運算
這些都是算術運算方法,需要你自己為類設計具體運算代碼。有些Python內置數據類型,比如int就帶有這些方法。Python支持運算符的重載,也就是重寫。
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Vector:def __init__(self, a, b):self.a = aself.b = bdef __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)13. __author__
__author__代表作者信息!類似的特殊成員還有很多,就不羅列了。
#!/usr/bin/env python # -*- coding:utf-8 -*-""" a test module """ __author__ = "Jack"def show():print(__author__)show()14. __slots__
Python作為一種動態語言,可以在類定義完成和實例化后,給類或者對象繼續添加隨意個數或者任意類型的變量或方法,這是動態語言的特性。例如:
def print_doc(self):print("haha")class Foo:passobj1 = Foo() obj2 = Foo() # 動態添加實例變量 obj1.name = "jack" obj2.age = 18 # 動態的給類添加實例方法 Foo.show = print_doc obj1.show() obj2.show()但是!如果我想限制實例可以添加的變量怎么辦?可以使__slots__限制實例的變量,比如,只允許Foo的實例添加name和age屬性。
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' def print_doc(self):print("haha")class Foo:__slots__ = ("name", "age")passobj1 = Foo() obj2 = Foo() # 動態添加實例變量 obj1.name = "jack" obj2.age = 18 obj1.sex = "male" # 這一句會彈出錯誤 # 但是無法限制給類添加方法 Foo.show = print_doc obj1.show() obj2.show()由于’sex’不在__slots__的列表中,所以不能綁定sex屬性,試圖綁定sex將得到AttributeError的錯誤。
Traceback (most recent call last):File "F:/Python/pycharm/201705/1.py", line 14, in <module>obj1.sex = "male" AttributeError: 'Foo' object has no attribute 'sex'需要提醒的是,__slots__定義的屬性僅對當前類的實例起作用,對繼承了它的子類是不起作用的。想想也是這個道理,如果你繼承一個父類,卻莫名其妙發現有些變量無法定義,那不是大問題么?如果非要子類也被限制,除非在子類中也定義__slots__,這樣,子類實例允許定義的屬性就是自身的__slots__加上父類的__slots__。
Python的特殊成員和“魔法方法”還有很多,需要大家在平時使用和學習的過程中不斷積累和總結使用經驗。
總結
以上是生活随笔為你收集整理的Python 特殊成员和魔法方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python提升“技术逼格”的6个方法
- 下一篇: python教程:循环(while和fo