1. 程式人生 > >一文了解 Python 的 “Magic” 方法

一文了解 Python 的 “Magic” 方法

在以前的文章中,我聊過了Python的 __getitem__ 和 __setitem__ 方法。這些方法被稱為“魔法”方法、特殊方法或者dunger方法(譯者:國內書籍用“魔法”一詞較多)。那麼,什麼是魔法方法呢?這正是今天我們要說的內容。

P.S.你會再一次的深深的愛上Python語言。

也將是一篇較長的文章,來讓我們開始。

魔法方法究竟是什麼?

魔法方法是一種具有特殊魅力的正常方法。Python通過這些魔法方法可以賦予你的class魔力。這些魔法方法都是以雙下劃線(__)作為字首和字尾。坦率的講,其實這些方法並沒有什麼魔法,另外這些方法這Python的文件中也沒有較為詳細的介紹,因此,今天我們就來詳細的看一看這些方法。

魔法方法之初始化

所有的Python開發者都知道,__init__()是一個類(class)的第一個方法,也可以叫做建構函式。雖然,__init__()方法是第一個被建立的,但是它卻不是第一個被呼叫的執行的,__new__()方法才是最早被呼叫的方法。

  • __new__()方法:先讀取引數,如:類名稱,args,和kwargs。然後,__new__()方法把這些引數傳遞給對類名稱的__init__()方法。 語法:__new__(class_name, args, kwargs)
  • __init__()方法:是類的初始化方法或構造方法,這也幾乎用於全域性的初始化目的。 語法:__init__(self, args, kwargs)
  • __del__()方法:類的解構函式。切記,這並不是定義del x,而是定義了一個物件被垃圾回收的行為。 語法:__del__(self)

看一個例子:

class SimpleInit(object):
    '''
        Class to initialize a list with a value
    '''
    def __init__(self, value=10):
        self._list = [value]

    def __del__(self):
        del self._list

魔法方法之算術運算

算術運算是非常常見的,因此,如果你想建立屬於自己的資料結構,魔法方法會使你的實現更容易。例如:我們可以像這樣,some_list + some_list2,實現Python的列表(list)拼接。類似這種的有趣行為,我們可以通過魔法方法的算術運算實現定義。

  • __add__(self, other) 定義加法 (+)
  • __sub__(self, other) 定義減法 (-)
  • __mul__(self, other) 定義乘法 (*)
  • __floordiv__(self, other) 定義整除法 (//)
  • __div__(self, other) 定義浮點型除法 (/)
  • __mod__(self, other) 定義取餘模運算 (%)
  • __and__(self, other) 定義按位與 (&)
  • __or__(self, other) 定義按位或 (|)
  • __xor__(self, other) 定義按位異或 (^)
  • __pow__(self, other) 定義指數運算 (**)
  • __lshift__(self, other) 定義按位左移 (<<)
  • __rshift__(self, other) 定義按位右移 (>>)

例如:

class SimpleAdder(object):
    def __init__(self, elements=[]):
        self._list = elements
        
    def __add__(self, other):
        return self._list + other._list
    
    def __str__(self):
        return str(self._list)
    a = SimpleAdder(elements=[1,2,3,4])b = SimpleAdder(elements=[2, 3, 4])print(a + b)    # [1, 2, 3, 4, 2, 3, 4]

魔法方法之增量賦值

Python不僅允許我們定義算術運算,也允許我們定義增量賦值運算。如果你不知道什麼是增量賦值是什麼?那麼我們來看一個簡單的例子:

x = 5
    x += 1              # This first adds 5 and 1 and then assigns it back to 'x'

因此有的時候,你可能想寫一些自自定義邏輯實現增量賦值操作。魔法方法支援的運算子有:

  • __iadd__(self, other) 定義加法 (+=)
  • __isub__(self, other) 定義減法 (-=)
  • __imul__(self, other) 定義乘法 (*=)
  • __ifloordiv__(self, other) 定義整除法 (//=)
  • __idiv__(self, other) 定義浮點型除法 (/=)
  • __imod__(self, other) 定義取模運算 (%=)
  • __iand__(self, other) 定義按位與 (&=)
  • __ior__(self, other) 定義按位或 (|=)
  • __ixor__(self, other) 定義按位異或(^=)
  • __ipow__(self, other) 定義指數運算 (**=)
  • __ilshift__(self, other) 定義按位左移 (<<=)
  • __irshift__(self, other) 定義按位右移 (>>=)

 

魔法方法之比較運算

Python有一組廣泛的魔術方法實現比較。我們可以覆蓋預設的比較行為,來定義使用物件的引用方法。下面是比較魔法方法的列表:

  • __eq__(self, other) 幫助檢查兩個物件的相等。它定義了相等運算 (==)
  • __ne__(self, other) 定義了不等運算 (!=)
  • __lt__(self, other) 定義了小於運算 (<)
  • __gt__(self, other) 定義了大於運算 (>)
  • __le__(self, other) 定義了小於等於運算 (<=)
  • __ge__(self, other) 定義了大於等於運算 (>=)

例如:

class WordCounter(object):
    '''
        Simple class to count number of words in a sentence
    '''
    def __init__(self, sentence):
        # split the sentence on ' '
        if type(sentence) != str:
            raise TypeError('The sentence should be of type str and not {}'.format(type(sentence)))
        self.sentence = sentence.split(' ')
        self.count    = len(self.sentence)
        
    def __eq__(self, other_class_name):
        '''
            Check the equality w.r.t length of the list with other class
        '''
        return self.count == other_class_name.count
    
    def __lt__(self, other_class_name):
        '''
            Check the less-than w.r.t length of the list with other class
        '''
        return self.count < other_class_name.count
    
    def __gt__(self, other_class_name):
        '''
            Check the greater-than w.r.t length of the list with other class
        '''
        return self.count > other_class_name.count
    word = WordCounter('Omkar Pathak')print(word.count)

魔法方法之型別轉換

很多時候開發人員需要隱性的轉換變數型別,來滿足最要想要的結果。Python是關心你內在資料的型別的一種動態型別語言,除此之外,Python也關心你,哈哈!如果你想要自定義屬於自己的方法,可以藉助如下方法:

  • __int__(self) 定義型別轉化為 int
  • __long__(self) 定義型別轉化為 long
  • __float__(self) 定義型別轉化為 float
  • __complex__(self) 定義型別轉化為 complex(複數)
  • __oct__(self) 定義型別轉化為 octal(八進位制)
  • __hex__(self) 定義型別轉化為 (十六進位制)
  • __index__(self) 定義型別轉化為一種int, 當物件被用於切片表示式( a slice expression)時

 

最常用的魔法方法

這裡有一些魔法方法你應該經常遇到:

  • __str__(self) 定義了str()行為。例如,當你呼叫print(object_name),無論object_name是什麼都會被__str__()執行
  • __repr__(self) 定義了repr()行為。這個很大程度上類似於__str__()。這兩個之間的主要區別是,str()主要是人類可讀的和repr()是機器可讀的
  • __hash__(self) 定義了行為呼叫hash()
  • __len__(self) 返回容器的長度
  • __getitem__(self) 和 __setitem__(self). 更多內容可以詳見我以前的部落格文章。
  • __delitem__(self, key) 定義了一個刪除一個專案的行為. 例如, del _list[3]
  • __iter__(self) 返回一個迭代容器
class CustomList(object):
    def __init__(self, elements=0):
        self.my_custom_list = [0] * elements

    def __str__(self):
        return str(self.my_custom_list)

    def __setitem__(self, index, value):
        self.my_custom_list[index] = value

    def __getitem__(self, index):
        return "Hey you are accessing {} element whose value is: {}".format(index, self.my_custom_list[index])

    def __iter__(self):
        return iter(self.my_custom_list)obj = CustomList(12)obj[0] = 1print(obj[0])print(obj)

把這些有魔法的Python禮物送給你~!

 

coding 快樂!