創建類magic method:
__new__:創建一個對象時真正第一個調用的方法,該方法爲類方法,會創建一個對象並吧其與傳入參數一併交給__init__
__init__:初始化對象,對__new__創建的對象進行一些初始化操作
__del__:在對象不再被使用的時候自動進行進行調用,可以執行一些善後工作,但是由於不知道該方法會在什麼時候被執行,所以其可控性差,所以不建議被使用
比較類migic method:
__cmp__:可以定義所有比較,當大於時返回正數,小於時返回負數,等於時返回0
__eq__:定義等於==
__ne__:定義不等!=
__lt__:定義小於<
__gt__:定義大於>
__le__:定義小於等於<=
__ge__:定義大於等於>=
Numeric magic methods:(具體翻譯不明確,運算符?)
一元運算符:
__pos__(self):相當於+
__neg__(self):相當於-
__abs__(self):使用abs()方法時調用
__invert__(self):反轉,即NOT,比如NOT 0001 = 1000
Normal arithmetic operators:(一般常用運算符)
__add__(self, other):實現加法,跟__pos__的差別?
__sub__(self, other):實現減法
__mul__(self, other):實現乘法
__floordiv__(self, other):實現了整數的除法使用/ /操作符。。。(有道翻譯)
__div__(self, other):實現除法使用/操作符號(跟上面的區別是返回結果不是整數)
__truediv__(self, other):實現真正的除法?只有當從__future__導入division的時候纔會工作
__mod__(self, other):實現取餘通過%操作符
__divmod__(self, other):實現長除法(?)使用divmod()內置函數的時候
__pow__(self, other):實現指數操作使用**操作符
__lshift__(self, other):實現左移操作使用<<操作符
__rshift__(self, other):實現右移操作使用>>操作符
__and__(self, other):實現與操作使用&操作符
__or__(self, other):實現或操作使用|操作符
__xor__(self, other):實現xor操作使用^操作符
以上所有方法前面加上r即是自身作爲第二個操作數時的實現,如__radd__就是當other+me時調用,而__add__是me+other時調用,一般時候這兩個實現是一樣的,所以只要其中一個調用另外一個方法就行
Augmented assignment(累加累減之流):
__iadd__(self, other):定義i++
__isub__(self, other):定義i--
__imul__(self, other):定義i**
以此類推,以上的一般運算都有相應的累計運算
Type conversion magic methods:(用於類型轉換)
__int__(self):__float__(self):__long__(self):分別對應int(), float(), long()方法作用於該對象上時返回值,注意,只能返回對應的類型
__complex__(self):複雜?
__oct__(self):八進制
__hex__(self):十六進制
__index__(self):當對象是被應用在切片表達式中時,實現整形強制轉換,如果你定義了一個可能在切片時用到的定製的數值型,你應該定義 __index__(博主表示難以理解,貌似是用在列表中的?沒有找到實際的例子)
__trunc__(self):當調用math.trunc(self)時得到調用,通常返回一個long型
__coerce__(self):
表現你的類¶
如果有一個字符串來表示一個類將會非常有用。在Python中,有很多方法可以實現類定義內置的一些函數的返回值。 __str__(self) 定義當 str() 調用的時候的返回值 __repr__(self) 定義 repr() 被調用的時候的返回值。 str() 和 repr() 的主要區別在於 repr() 返回的是機器可讀的輸出,而 str() 返回的是人類可讀的。 __unicode__(self) 定義當 unicode() 調用的時候的返回值。 unicode() 和 str() 很相似,但是返回的是unicode字符串。注意,如a果對你的類調用
str() 然而你只定義了 __unicode__() ,那麼將不會工作。你應該定義 __str__() 來確保調用時能返回正確的值。
__hash__(self) 定義當 hash() 調用的時候的返回值,它返回一個整形,用來在字典中進行快速比較 __nonzero__(self) 定義當 bool() 調用的時候的返回值。本方法應該返回True或者False,取決於你想讓它返回的值。
控制屬性訪問¶
許多從其他語言轉到Python的人會抱怨它缺乏類的真正封裝。(沒有辦法定義私有變量,然後定義公共的getter和setter)。Python其實可以通過魔術方法來完成封裝。我們來看一下:
__getattr__(self, name) 你可以定義當用戶試圖獲取一個不存在的屬性時的行爲。這適用於對普通拼寫錯誤的獲取和重定向,對獲取一些不建議的屬性時候給出警告(如果你願意你也可以計算並且給出一個值)或者處理一個 AttributeError 。只有當調用不存在的屬性的時候會被返回。然而,這不是一個封裝的解決方案。 __setattr__(self, name, value) 與 __getattr__ 不同, __setattr__ 是一個封裝的解決方案。無論屬性是否存在,它都允許你定義對對屬性的賦值行爲,以爲這你可以對屬性的值進行個性定製。但是你必須對使用
__setattr__ 特別小心。之後我們會詳細闡述。 __delattr__ 與 __setattr__ 相同,但是功能是刪除一個屬性而不是設置他們。注意與 __setattr__ 相同,防止無限遞歸現象發生。(在實現 __delattr__ 的時候調用 del self.name 即會發生) __getattribute__(self, name) __getattribute__ 與它的同伴 __setattr__ 和 __delattr__ 配合非常好。但是我不建議使用它。只有在新類型類定義中才能使用
__getattribute__ (在最新版本Python中所有的類都是新類型,在老版本中你可以通過繼承 object 來製作一個新類。這樣你可以定義一個屬性值的訪問規則。有時也會產生一些帝歸現象。(這時候你可以調用基類的 __getattribute__ 方法來防止此現象的發生。)它可以消除對 __getattr__ 的使用,如果它被明確調用或者一個 AttributeError 被拋出,那麼當實現 __getattribute__ 之後才能被調用。此方法是否被使用其實最終取決於你的選擇。)我不建議使用它因爲它的使用機率較小(我們在取得一個值而不是設置一個值的時候有特殊的行爲是非常罕見的。)而且它不能避免會出現bug。
在進行屬性訪問控制定義的時候你可能會很容易的引起一個錯誤。考慮下面的例子。
def __setattr__(self, name, value):
self.name = value
#每當屬性被賦值的時候, ``__setattr__()`` 會被調用,這樣就造成了遞歸調用。
#這意味這會調用 ``self.__setattr__('name', value)`` ,每次方法會調用自己。這樣會造成程序崩潰。
def __setattr__(self, name, value):
self.__dict__[name] = value #給類中的屬性名分配值
#定製特有屬性
Python的魔術方法非常強大,然而隨之而來的則是責任。瞭解正確的方法去使用非常重要。
所以我們對於定製屬性訪問權限瞭解了多少呢。它不應該被輕易的使用。實際上,它非常強大。但是它存在的原因是:Python 不會試圖將一些不好的東西變得不可能,而是讓它們難以實現。自由是至高無上的,所以你可以做任何你想做的。一下是一個特別的屬性控制的例子(我們使用 super 因爲不是所有的類都有 __dict__ 屬性):
class AccessCounter:
'''一個包含計數器的控制權限的類每當值被改變時計數器會加一'''
def __init__(self, val):
super(AccessCounter, self).__setattr__('counter', 0)
super(AccessCounter, self).__setattr__('value', val)
def __setattr__(self, name, value):
if name == 'value':
super(AccessCounter, self).__setattr__('counter', self.counter + 1)
#如果你不想讓其他屬性被訪問的話,那麼可以拋出 AttributeError(name) 異常
super(AccessCounter, self).__setattr__(name, value)
def __delattr__(self, name):
if name == 'value':
super(AccessCounter, self).__setattr__('counter', self.counter + 1)
super(AccessCounter, self).__delattr__(name)]