python進階之魔法函數


__repr__

Python中這個__repr__函數,對應repr(object)這個函數,返回一個可以用來表示對象的可打印字符串.
如果我們直接打印一個類,向下面這樣

class A():
    def __init__(self,name=None,id=1):
        self.id=id
        self.name=name

if __name__ == '__main__':
    a=A()
    print(a)

輸出結果

<__main__.A object at 0x0000018DF8E7EAC8>

不是很友好,返回了一個對象的內存地址。
我們改成下面再次輸出

class A():
    def __init__(self,name=None,id=1):
        self.id=id
        self.name=name
    def __repr__(self):
        return "進入函數"

if __name__ == '__main__':
    print(A())

輸出結果

進入函數

__str__

class A():
    def __init__(self,name=None,id=1):
        self.id=id
        self.name=name
    def __str__(self):
        return "進入函數"

if __name__ == '__main__':
    print(A())

輸出結果

進入函數

比較repr和str

上面我們發現在print的時候,兩個魔法函數顯示的效果是一樣的,那這兩個魔法函數區別在哪呢,__repr__和__str__這兩個方法都是用於顯示的,__str__是面向用戶的,而__repr__面向程序員。在print的時候兩者項目一樣,但是在交互命令下
__repr__同樣有着print的效果,但是__str__還是輸出對象內存地址。也就說在交互式命令下我們可以看到其效果,另外__str__ 方法其實調用了 __repr__ 方法。

__getitem__

如果在類中定義了getitem__()方法,那么他的實例對象(假設為A)就可以這樣A[key]取值。當實例對象做A[key]運算時,就會調用類中的__getitem()方法。

class A():
    def __init__(self,name=None,id=1):
        self.id=id
        self.name=name
    def __repr__(self):
        return "進入函數"
    def __getitem__(self, item):
       return item



if __name__ == '__main__':
    a=A('lisa','123')
    print(a['name'])
    print(a[124])

輸出

name
124

實例對象的key不管是否存在都會調用類中的__getitem__()方法。而且返回值就是__getitem__()方法中規定的return值。也就是說如果getitem里的方法寫的不好就沒有了意義了。
我們修改下代碼,改變getitem的return的值

class A():
    def __init__(self,name=None,id=1):
        self.id=id
        self.name=name
    def __repr__(self):
        return "進入函數"
    def __getitem__(self, item):
       return self.__dict__[item]



if __name__ == '__main__':
    a=A('lisa','123')
    print(a['name'])
    print(a[123])

輸出

lisa
keyerror:123

輸出了lisa和一個異常,改后的getitem做了什么事呢,
self.__dict__,是獲取當前實例的所有屬性的字典格式,后面的[item]就是取其對於的鍵值,這里我傳了個name,實際就是取name屬性的值也就是lisa。
對於123因為不存在這個屬性所有報錯了。這也是字典內部實現的一部分。

再來看一個例子,代碼里已經加入了注釋:

import collections

Card = collections.namedtuple('Card', ['rank''suit'])


# 具名元組動態創建一個類Card,並含有兩個屬性rank和suit
# 用以構建只有少數屬性但是沒有方法的對象

class FrenchDeck:
    ranks = [str(n) for n in range(211)] + list('JQKA')  # 撲克牌2到A組成的列表
    suits = 'spades diamonds clubs hearts'.split()  # 四種花色

    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]  # 笛卡爾積,13*4=52(除去兩個王)

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        # 調用f[0]時會進入
        return self._cards[position]


if __name__ == '__main__':
    f = FrenchDeck()

    print(f[0])
    # 在這里f[0]實際是f.__getitem__(0)

輸出

Card(rank='2', suit='spades')

我們發現這個例子中還有一個__len__,那這個方法是干嘛的呢,我們繼續往下看

__len__

在上面的例子中我們使用該方法,這個方法會在什么情況下發生呢,一個小例子來說明。

class B():

    def __init__(self):
        self.a_list = range(10)

    def __len__(self):
        return len(self.a_list)


if __name__ == '__main__':
     b = B()
     print(len(b))
     #在這里等價於
     #print(b.__len__())

輸出

10

我們在調用len方法的時候會調用__len__。

__setitem__

__setitem__(self,key,value):該方法應該按一定的方式存儲和key相關的value。在設置類實例屬性時自動調用的。

class B():

    def __init__(self):
        self.a_list = range(10)

    def __setitem__(self, key, value):
        self.__dict__[key] = value


def cfun(a, b, c):
    print("新加入函數c")


if __name__ == '__main__':
    b = B()
    b['a_list'] = "123"  # 這個會調用B類的\__setitem_方法_
    B.__setitem__ = cfun  # 改變settime方式變為cfun這個函數
    b['a_list'] = "123"  # 這次實際會調用cfun函數
    print(b.a_list)

輸出

新加入函數c
123

__delitem__

執行del函數的時候會調用,如果繼承了 繼承
abc.MutableSequence的類就必須實現 __delitem__ 方法,這是 MutableSequence 類的一個抽象方法。

__eq__

a == b等同於a.__eq__(b)。
你可以在自己的類中定義 __eq__ 方法,決定 == 如何比較
實例。如果不覆蓋 __eq__ 方法,那么從 object 繼承的方法比較


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM