有的,你只需要根據以下教程,死磕即可

基礎篇

https://digolds.cn/article/001532966908032f8b7750f6b5a42bba8e229e35c62eeb4000https://digolds.cn/article/0015329679477883725095d6280470dadb44fdc52f6df0a000

https://digolds.cn/article/0015330450692424e883ade8a82474ebab2989fc8744c04000

https://digolds.cn/article/00153304521997150a084ea8dd74beb9e63677c50c57577000https://digolds.cn/article/0015330454058898931f18f10334447aa2300b989c5e03d000https://digolds.cn/article/001533045684950c69e78de8779416b9e3acaeb60d5571e000https://digolds.cn/article/001533046006354e3ae31c504c24795a0f0f1c6b9149b5a000https://digolds.cn/article/001533046224219b72c2935850a477d8128ebc020ee2f9b000https://digolds.cn/article/0015330462500950b61ac87b6af47cab96a4c6948c5fe60000https://digolds.cn/article/00153304634054659aba3978d224fc1a160704977aac905000https://digolds.cn/article/0015330463733222899569f64104326969d4b2127adca5b000https://digolds.cn/article/001533046416848743e7b2353c3435895f6aff2963d75a0000

https://digolds.cn/article/0015474811434801393eafd241749a188d90610de72837d000

高階篇

https://digolds.cn/article/00153742858683510fbeb6ea1e149159f34115a9c08eeed000https://digolds.cn/article/001537428666340d295ba9535284ff38c1b4ecd2707bba8000https://digolds.cn/article/001537428719664a71b89acdfcf480790f57136e1da4894000https://digolds.cn/article/00153742873940233f0c48dae07473993817e8b9b895dec000https://digolds.cn/article/00153742880755101f1b27c363d4efcb214ffdc044d8acf000https://digolds.cn/article/001537428821346e1de8fc3a9854c24a24e9ef86591b0bc000https://digolds.cn/article/0015568497340034e5331b0b3f349b6b7c30267bffe34ae000

實用篇

https://digolds.cn/article/001606129404456a408d4a0c42a40eeb4de5358651801b7000

https://digolds.cn/article/001606189903662e54f176ea98449cc8c4b517cbca09f3d000https://digolds.cn/article/0016072261868132b8bb918aea2411d9799f7fafc14ff61000

想要看懂就要學會Python,如果自身都學不會Python,那就算怎麼去看也是看不懂的。

就算是不學會Python,也要把Python的基礎學完,這樣才能看懂Python的代碼,還不是全都能看懂,因為看得懂的,都是學到過的,或者說是用過,才能認識。

至於說怎麼學習,可以先去視頻上看一遍,把Python基礎知識看一遍,如果看一遍之後產生了一些興趣再去看書學習一遍,或者是幾遍,至於書中的練習題,以及例題都打幾遍。

再提供一些學習的幫助:

1.在學習初期制定一定的學習計劃,這樣才能有規律的學習,養成習慣,對後續的學習會更加有利。

2.掌握正確的學習方法,只有一個好的學習方法才能讓學習效率更高,把時間最大化的利用起來。

發佈於 04-20繼續瀏覽內容知乎發現更大的世界打開Chrome繼續軟體質量保障軟體質量保障?

阿里巴巴集團 測試專家

掌握Python編程基礎

Python編程九:代碼調試

Python編程八:異常處理

Python編程七:如何讓繁瑣的工作自動化?

Python編程六:面向對象編程

Python編程五:數據結構

Python編程四:認識函數

Python編程三:語句控制

Python編程二:變數與運算符

Python編程一:初識Python


掌握Python編程基礎

Python編程九:代碼調試

Python編程八:異常處理

Python編程七:如何讓繁瑣的工作自動化?

Python編程六:面向對象編程

Python編程五:數據結構

Python編程四:認識函數

Python編程三:語句控制

Python編程二:變數與運算符

Python編程一:初識Python


想要看懂Python,最起碼得先把Python的基礎語句學會,也就是Python基礎,連基礎都不會又怎麼可能看得懂呢 ,就算注釋標的在清楚也是看不懂的。

所以想要讀懂Python就要把基礎學明白,我有一個辦法可以很快的學完Python的基礎,和其他的學習方式來比,算是不叫快的了,而且也比較方便。

在剛剛開始學習Python的時候,先用視頻過一遍,把Python的知識學習一遍,並且能跟隨視頻去做一些練習,這樣能夠加深理解,在視頻看完一遍以後,在使用書籍再來學習一遍,這一遍是為了基礎中的細節,因為視頻學習的速度可能太快了,導致一些細節不太準確,所以用書籍在學一遍。

然後再把其他的知識複習一遍,這一次要準確的多 最好是能把書中的例題都打幾遍。

這樣學完的基礎可以說是非常的穩固,而且如果自身天賦夠高,這樣的學習方式也能節約很多的時間。


本指南歸納於我的幾個月的方法,主題是 魔法方法

什麼是魔法方法呢?它們在面向對象的Python的處處皆是。它們是一些可以讓你對類添加「魔法」的特殊方法。它們經常是兩個下劃線包圍來命名的(比如 __init____lt__ )。但是現在沒有很好的文檔來解釋它們。所有的魔法方法都會在Python的官方文檔中找到,但是它們組織鬆散。而且很少會有示例(有的是無聊的語法描述, 語言參考)。

所以,為了修復我感知的Python文檔的缺陷,我開始提供更為通俗的,有示例支持的Python魔法方法指南。我一開始 寫了一些博文,現在我把這些博文總起來成為一篇指南。

希望你喜歡這篇指南,一篇友好、通俗易懂的Python魔法方法指南!(註:原文較長,會分成兩篇分享

01. 構造方法

我們最為熟知的基本的魔法方法就是 __init__ ,我們可以用它來指明一個對象初始化的行為。然而,當我們調用 x = SomeClass() 的時候, __init__ 並不是第一個被調用的方法。事實上,第一個被調用的是 __new__ ,這個 方法才真正地創建了實例。當這個對象的生命周期結束的時候, __del__ 會被調用。讓我們近一步理解這三個方法:

  • __new__(cls,[…)

    __new__ 是對象實例化時第一個調用的方法,它只取下 cls 參數,並把其他參數傳給 __init____new__ 很少使用,但是也有它適合的場景,尤其是當類繼承自一個像元組或者字元串這樣不經常改變的類型的時候。我不打算深入討論 __new__ ,因為它並不是很有用, Python文檔 中 有詳細的說明。

  • __init__(self,[…])類的初始化方法。它獲取任何傳給構造器的參數(比如我們調用 x = SomeClass(10, foo) , __init__ 就會接到參數 10 和 foo 。__init__ 在Python的類定義中用的最多。
  • __del__(self)__new____init__ 是對象的構造器, __del__ 是對象的銷毀器。它並非實現了語句 del x (因此該語句不等同於 x.__del__())。而是定義了當對象被垃圾回收時的行為。當對象需要在銷毀時做一些處理的時候這個方法很有用,比如 socket 對象、文件對象。但是需要注意的是,當Python解釋器退出但對象仍然存活的時候, __del__ 並不會 執行。所以養成一個手工清理的好習慣是很重要的,比如及時關閉連接。

這裡有個 __init____del__ 的例子:

from os.path import join

class FileObject: 文件對象的裝飾類,用來保證文件被刪除時能夠正確關閉。 def __init__(self, filepath=~, filename=sample.txt): # 使用讀寫模式打開filepath中的filename文件 self.file = open(join(filepath, filename), r+) def __del__(self):

self.file.close()

del self.file

02. 操作符

使用Python魔法方法的一個巨大優勢就是可以構建一個擁有Python內置類型行為的對象。這意味著你可以避免使用非標準的、醜陋的方式來表達簡單的操作。在一些語言中,這樣做很常見:

if instance.equals(other_instance):
# do something

你當然可以在Python也這麼做,但是這樣做讓代碼變得冗長而混亂。不同的類庫可能對同一種比較操作採用不同的方法名稱,這讓使用者需要做很多沒有必要的工作。運用魔法方法的魔力,我們可以定義方法 __eq__

if instance == other_instance:

# do something

這是魔法力量的一部分,這樣我們就可以創建一個像內建類型那樣的對象了!

2.1 比較操作符

Python包含了一系列的魔法方法,用於實現對象之間直接比較,而不需要採用方法調用。同樣也可以重載Python默認的比較方法,改變它們的行為。下面是這些方法的列表:

  • __cmp__(self, other)__cmp__ 是所有比較魔法方法中最基礎的一個,它實際上定義了所有比較操作符的行為(&__cmp__ 應該在 self &< other 時返回一個負整數,在 self == other 時返回0,在 self &> other 時返回正整數。最好只定義你所需要的比較形式,而不是一次定義全部。如果你需要實現所有的比較形式,而且它們的判斷標準類似,那麼 __cmp__ 是一個很好的方法,可以減少代碼重複,讓代碼更簡潔。
  • __eq__(self, other)

    定義等於操作符(==)的行為。

  • __ne__(self, other)定義不等於操作符(!=)的行為。
  • __lt__(self, other)定義小於操作符(&
  • __gt__(self, other)定義大於操作符(&>)的行為。
  • __le__(self, other)定義小於等於操作符(&
  • __ge__(self, other)定義大於等於操作符(&>)的行為。

舉個例子,假如我們想用一個類來存儲單詞。我們可能想按照字典序(字母順序)來比較單詞,字元串的默認比較行為就是這樣。我們可能也想按照其他規則來比較字元串,像是長度,或者音節的數量。在這個例子中,我們使用長度作為比較標準,下面是一種實現:

class Word(str):
單詞類,按照單詞長度來定義比較行為

def __new__(cls, word):
# 注意,我們只能使用 `__new__` ,因為str是不可變類型
# 所以我們必須提前初始化它(在實例創建時)
if in word:
print Value contains spaces. Truncating to first space.
word = word[:word.index( )]
# Word現在包含第一個空格前的所有字母
return str.`__new__`(cls, word)

def __gt__(self, other):
return len(self) &> len(other)
def __lt__(self, other):
return len(self) &< len(other) def __ge__(self, other): return len(self) &>= len(other)
def __le__(self, other):
return len(self) &<= len(other)

現在我們可以創建兩個 Word 對象( Word(foo) 和 Word(bar))然後根據長度來比較它們。注意我們沒有定義 __eq____ne__ ,這是因為有時候它們會導致奇怪的結果(很明顯, Word(foo) == Word(bar) 得到的結果會是true)。根據長度測試是否相等毫無意義,所以我們使用 str 的實現來比較相等。

從上面可以看到,不需要實現所有的比較魔法方法,就可以使用豐富的比較操作。標準庫還在 functools 模塊中提供了一個類裝飾器,只要我們定義 __eq__ 和另外一個操作符( __gt__, __lt__ 等),它就可以幫我們實現比較方法。這個特性只在 Python 2.7 中可用。當它可用時,它能幫助我們節省大量的時間和精力。要使用它,只需要它 @total_ordering 放在類的定義之上就可以了

2.2 數值操作符

就像你可以使用比較操作符來比較類的實例,你也可以定義數值操作符的行為。固定好你的安全帶,這樣的操作符真的有很多。看在組織的份上,我把它們分成了五類:一元操作符,常見算數操作符,反射算數操作符(後面會涉及更多),增強賦值操作符,和類型轉換操作符。

一元操作符

一元操作符只有一個操作符。

  • __pos__(self)實現取正操作,例如 +some_object。
  • __neg__(self)實現取負操作,例如 -some_object。
  • __abs__(self)實現內建絕對值函數 abs() 操作。
  • __invert__(self)實現取反操作符 ~。
  • __round__(self, n)實現內建函數 round() ,n 是近似小數點的位數。
  • __floor__(self)實現 math.floor() 函數,即向下取整。
  • __ceil__(self)實現 math.ceil() 函數,即向上取整。
  • __trunc__(self)實現 math.trunc() 函數,即距離零最近的整數。

常見算數操作符

現在,我們來看看常見的二元操作符(和一些函數),像+,-,*之類的,它們很容易從字面意思理解。

  • __add__(self, other)實現加法操作。
  • __sub__(self, other)實現減法操作。
  • __mul__(self, other)實現乘法操作。
  • __floordiv__(self, other)實現使用 // 操作符的整數除法。
  • __div__(self, other)實現使用 / 操作符的除法。
  • __truediv__(self, other)實現 true 除法,這個函數只有使用 from __future__ import division 時才有作用。
  • __mod__(self, other)實現 % 取余操作。
  • __divmod__(self, other)實現 divmod 內建函數。
  • __pow__實現 ** 操作符。
  • __lshift__(self, other)實現左移位運算符 &
  • __rshift__(self, other)實現右移位運算符 &>&> 。
  • __and__(self, other)實現按位與運算符 。
  • __or__(self, other)實現按位或運算符 | 。
  • __xor__(self, other)實現按位異或運算符 ^ 。

反射算數運算符

還記得剛才我說會談到反射運算符嗎?可能你會覺得它是什麼高端霸氣上檔次的概念,其實這東西挺簡單的,下面舉個例子:

some_object + other

這是「常見」的加法,反射是一樣的意思,只不過是運算符交換了一下位置:

other + some_object

所有反射運算符魔法方法和它們的常見版本做的工作相同,只不過是處理交換連個操作數之後的情況。絕大多數情況下,反射運算和正常順序產生的結果是相同的,所以很可能你定義 __radd__ 時只是調用一下 __add__。注意一點,操作符左側的對象(也就是上面的 other )一定不要定義(或者產生 NotImplemented 異常) 操作符的非反射版本。例如,在上面的例子中,只有當 other 沒有定義 __add__ 時 some_object.__radd__ 才會被調用。

  • __radd__(self, other)實現反射加法操作。
  • __rsub__(self, other)實現反射減法操作。
  • __rmul__(self, other)實現反射乘法操作。
  • __rfloordiv__(self, other)實現使用 // 操作符的整數反射除法。
  • __rdiv__(self, other)實現使用 / 操作符的反射除法。
  • __rtruediv__(self, other)實現 true 反射除法,這個函數只有使用 from __future__ import division 時才有作用。
  • __rmod__(self, other)實現 % 反射取余操作符。
  • __rdivmod__(self, other)實現調用 divmod(other, self) 時 divmod 內建函數的操作。
  • __rpow__實現 ** 反射操作符。
  • __rlshift__(self, other)實現反射左移位運算符 &
  • __rshift__(self, other)實現反射右移位運算符 &>&> 的作用。
  • __rand__(self, other)實現反射按位與運算符 。
  • __ror__(self, other)實現反射按位或運算符 | 。
  • __rxor__(self, other)實現反射按位異或運算符 ^ 。

增強賦值運算符

Python同樣提供了大量的魔法方法,可以用來自定義增強賦值操作的行為。或許你已經了解增強賦值,它融合了「常見」的操作符和賦值操作,如果你還是沒聽明白,看下面的例子:

x = 5

x += 1 # 也就是 x = x + 1

這些方法都應該返回左側操作數應該被賦予的值(例如, a += b __iadd__ 也許會返回 a + b ,這個結果會被賦給 a ),下面是方法列表:

  • __iadd__(self, other)實現加法賦值操作。
  • __isub__(self, other)實現減法賦值操作。
  • __imul__(self, other)實現乘法賦值操作。
  • __ifloordiv__(self, other)實現使用 //= 操作符的整數除法賦值操作。
  • __idiv__(self, other)實現使用 /= 操作符的除法賦值操作。
  • __itruediv__(self, other)實現 true 除法賦值操作,這個函數只有使用 from __future__ import division 時才有作用。
  • __imod__(self, other)實現 %= 取余賦值操作。
  • __ipow__實現 **= 操作。
  • __ilshift__(self, other)實現左移位賦值運算符 &
  • __irshift__(self, other)實現右移位賦值運算符 &>&>= 。
  • __iand__(self, other)實現按位與運算符 = 。
  • __ior__(self, other)實現按位或賦值運算符 | 。
  • ixor(self, other)實現按位異或賦值運算符 ^= 。

類型轉換操作符

Python也有一系列的魔法方法用於實現類似 float() 的內建類型轉換函數的操作。它們是這些:

  • __int__(self)實現到int的類型轉換。
  • __long__(self)實現到long的類型轉換。
  • __float__(self)實現到float的類型轉換。
  • __complex__(self)實現到complex的類型轉換。
  • __oct__(self)實現到八進位數的類型轉換。
  • __hex__(self)實現到十六進位數的類型轉換。
  • __index__(self)實現當對象用於切片表達式時到一個整數的類型轉換。如果你定義了一個可能會用於切片操作的數值類型,你應該定義 index
  • __trunc__(self)當調用 math.trunc(self) 時調用該方法, trunc 應該返回 self 截取到一個整數類型(通常是long類型)的值。
  • __coerce__(self)該方法用於實現混合模式算數運算,如果不能進行類型轉換, coerce 應該返回 None 。反之,它應該返回一個二元組 self 和 other ,這兩者均已被轉換成相同的類型。

03. 類的表示

使用字元串來表示類是一個相當有用的特性。在Python中有一些內建方法可以返回類的表示,相對應的,也有一系列魔法方法可以用來自定義在使用這些內建函數時類的行為。

  • __str__(self)定義對類的實例調用 str() 時的行為。
  • __repr__(self)定義對類的實例調用 repr() 時的行為。str() 和 repr() 最主要的差別在於「目標用戶」。repr() 的作用是產生機器可讀的輸出(大部分情況下,其輸出可以作為有效的Python代碼),而 str() 則產生人類可讀的輸出。
  • __unicode__(self)定義對類的實例調用 unicode() 時的行為。unicode() 和 str() 很像,只是它返回unicode字元串。注意,如果調用者試圖調用 str() 而你的類只實現了 __unicode__() ,那麼類將不能正常工作。所有你應該總是定義 __str__() ,以防有些人沒有閑情雅緻來使用unicode。
  • __format__(self)定義當類的實例用於新式字元串格式化時的行為,例如, Hello, 0:abc!.format(a) 會導致調用 a.format(abc) 。當定義你自己的數值類型或字元串類型時,你可能想提供某些特殊的格式化選項,這種情況下這個魔法方法會非常有用。
  • __hash__(self)定義對類的實例調用 hash() 時的行為。它必須返回一個整數,其結果會被用於字典中鍵的快速比較。同時注意一點,實現這個魔法方法通常也需要實現 __eq__ ,並且遵守如下的規則:a == b 意味著 hash(a) == hash(b)。
  • __nonzero__(self)定義對類的實例調用 bool() 時的行為,根據你自己對類的設計,針對不同的實例,這個魔法方法應該相應地返回True或False。
  • __dir__(self)定義對類的實例調用 dir() 時的行為,這個方法應該向調用者返回一個屬性列表。一般來說,沒必要自己實現 __dir__ 。但是如果你重定義了 __getattr__ 或者 __getattribute__ (下個部分會介紹),乃至使用動態生成的屬性,以實現類的互動式使用,那麼這個魔法方法是必不可少的。

到這裡,我們基本上已經結束了魔法方法指南中無聊並且例子匱乏的部分。既然我們已經介紹了較為基礎的魔法方法,是時候涉及更高級的內容了。

04. 訪問控制

很多從其他語言轉向Python的人都抱怨Python的類缺少真正意義上的封裝(即沒辦法定義私有屬性然後使用公有的getter和setter)。然而事實並非如此。實際上Python不是通過顯式定義的欄位和方法修改器,而是通過魔法方法實現了一系列的封裝。

  • getattr(self, name)

當用戶試圖訪問一個根本不存在(或者暫時不存在)的屬性時,你可以通過這個魔法方法來定義類的行為。這個可以用於捕捉錯誤的拼寫並且給出指引,使用廢棄屬性時給出警告(如果你願意,仍然可以計算並且返回該屬性),以及靈活地處理AttributeError。只有當試圖訪問不存在的屬性時它才會被調用,所以這不能算是一個真正的封裝的辦法。

  • setattr(self, name, value)

__getattr__ 不同, __setattr__ 可以用於真正意義上的封裝。它允許你自定義某個屬性的賦值行為,不管這個屬性存在與否,也就是說你可以對任意屬性的任何變化都定義自己的規則。然後,一定要小心使用 __setattr__ ,這個列表最後的例子中會有所展示。

  • delattr(self, name)

這個魔法方法和 __setattr__幾乎相同,只不過它是用於處理刪除屬性時的行為。和 _setattr__ 一樣,使用它時也需要多加小心,防止產生無限遞歸(在 __delattr__ 的實現中調用 del self.name 會導致無限遞歸)。

  • getattribute(self, name)

__getattribute__ 看起來和上面那些方法很合得來,但是最好不要使用它。__getattribute__ 只能用於新式類。在最新版的Python中所有的類都是新式類,在老版Python中你可以通過繼承 object 來創建新式類。__getattribute__ 允許你自定義屬性被訪問時的行為,它也同樣可能遇到無限遞歸問題(通過調用基類的 __getattribute__ 來避免)。__getattribute__ 基本上可以替代 __getattr__ 。只有當它被實現,並且顯式地被調用,或者產生 AttributeError 時它才被使用。這個魔法方法可以被使用(畢竟,選擇權在你自己),我不推薦你使用它,因為它的使用範圍相對有限(通常我們想要在賦值時進行特殊操作,而不是取值時),而且實現這個方法很容易出現Bug。

自定義這些控制屬性訪問的魔法方法很容易導致問題,考慮下面這個例子:

def __setattr__(self, name. value):
self.name = value
# 因為每次屬性幅值都要調用 __setattr__(),所以這裡的實現會導致遞歸
# 這裡的調用實際上是 self.__setattr(name, value)。因為這個方法一直
# 在調用自己,因此遞歸將持續進行,直到程序崩潰

def __setattr__(self, name, value):
self.__dict__[name] = value # 使用 __dict__ 進行賦值
# 定義自定義行為

再次重申,Python的魔法方法十分強大,能力越強責任越大,了解如何正確的使用魔法方法更加重要。

到這裡,我們對Python中自定義屬性存取控制有了什麼樣的印象?它並不適合輕度的使用。實際上,它有些過分強大,而且違反直覺。然而它之所以存在,是因為一個更大的原則:Python不指望讓杜絕壞事發生,而是想辦法讓做壞事變得困難。自由是至高無上的權利,你真的可以隨心所欲。下面的例子展示了實際應用中某些特殊的屬性訪問方法(注意我們之所以使用 super 是因為不是所有的類都有 __dict__ 屬性):

class AccessCounter(object):

一個包含了一個值並且實現了訪問計數器的類 每次值的變化都會導致計數器自增 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)

05. 自定義序列

有許多辦法可以讓你的Python類表現得像是內建序列類型(字典,元組,列表,字元串等)。這些魔法方式是目前為止我最喜歡的。它們給了你難以置信的控制能力,可以讓你的類與一系列的全局函數完美結合。在了解激動人心的內容之前,首先你需要掌握一些預備知識。

既然講到創建自己的序列類型,就不得不說一說協議了。協議類似某些語言中的介面,裡面包含的是一些必須實現的方法。在Python中,協議完全是非正式的,也不需要顯式的聲明,事實上,它們更像是一種參考標準。

為什麼我們要講協議?因為在Python中實現自定義容器類型需要用到一些協議。首先,不可變容器類型有如下協議:想實現一個不可變容器,你需要定義 __len____getitem__ (後面會具體說明)。可變容器的協議除了上面提到的兩個方法之外,還需要定義 __setitem____delitem__ 。最後,如果你想讓你的對象可以迭代,你需要定義 __iter__ ,這個方法返回一個迭代器。迭代器必須遵守迭代器協議,需要定義 __iter__ (返回它自己)和 next 方法。

5.1 容器背後的魔法方法

  • __len__(self)返回容器的長度,可變和不可變類型都需要實現。
  • __getitem__(self, key)定義對容器中某一項使用 self[key] 的方式進行讀取操作時的行為。這也是可變和不可變容器類型都需要實現的一個方法。它應該在鍵的類型錯誤式產生 TypeError 異常,同時在沒有與鍵值相匹配的內容時產生 KeyError 異常。
  • __setitem__(self, key)定義對容器中某一項使用 self[key] 的方式進行賦值操作時的行為。它是可變容器類型必須實現的一個方法,同樣應該在合適的時候產生 KeyError 和 TypeError 異常。
  • __iter__(self, key)它應該返回當前容器的一個迭代器。迭代器以一連串內容的形式返回,最常見的是使用 iter() 函數調用,以及在類似 for x in container: 的循環中被調用。迭代器是他們自己的對象,需要定義 __iter__ 方法並在其中返回自己。
  • __reversed__(self)定義了對容器使用 reversed() 內建函數時的行為。它應該返回一個反轉之後的序列。當你的序列類是有序時,類似列表和元組,再實現這個方法,
  • __contains__(self, item)__contains__ 定義了使用 in 和 not in 進行成員測試時類的行為。你可能好奇為什麼這個方法不是序列協議的一部分,原因是,如果 contains 沒有定義,Python就會迭代整個序列,如果找到了需要的一項就返回 True 。
  • __missing__(self ,key)__missing__ 在字典的子類中使用,它定義了當試圖訪問一個字典中不存在的鍵時的行為(目前為止是指字典的實例,例如我有一個字典 d , george 不是字典中的一個鍵,當試圖訪問 d[george] 時就會調用 d.__missing__(george) )。

5.2 一個例子

讓我們來看一個實現了一些函數式結構的列表,可能在其他語言中這種結構更常見(例如Haskell):

class FunctionalList:
一個列表的封裝類,實現了一些額外的函數式
方法,例如head, tail, init, last, drop和take。

def __init__(self, values=None):
if values is None:
self.values = []
else:
self.values = values

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

def __getitem__(self, key):
# 如果鍵的類型或值不合法,列表會返回異常
return self.values[key]

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

def __delitem__(self, key):
del self.values[key]

def __iter__(self):
return iter(self.values)

def __reversed__(self):
return reversed(self.values)

def append(self, value):
self.values.append(value)

def head(self):
# 取得第一個元素
return self.values[0]

def tail(self):
# 取得除第一個元素外的所有元素
return self.valuse[1:]

def init(self):
# 取得除最後一個元素外的所有元素
return self.values[:-1]

def last(self):
# 取得最後一個元素
return self.values[-1]

def drop(self, n):
# 取得除前n個元素外的所有元素
return self.values[n:]

def take(self, n):
# 取得前n個元素
return self.values[:n]

就是這些,一個(微不足道的)有用的例子,向你展示了如何實現自己的序列。當然啦,自定義序列有更大的用處,而且絕大部分都在標準庫中實現了(Python是自帶電池的,記得嗎?),像 Counter , OrderedDict 和 NamedTuple 。


推薦閱讀:
相关文章