1. 程式人生 > 程式設計 >python 魔法函式例項及解析

python 魔法函式例項及解析

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,id=1):
    self.id=id
    self.name=name
  def __repr__(self):
    return "進入函式"

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

輸出結果

進入函式

__str__

class A():
  def __init__(self,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,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,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(2,11)] + 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():

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():

class B():
  def __init__(self):
    self.a_list = range(10)
  def __setitem__(self,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 繼承的方法比較

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。