您的位置:首頁>正文

一名神級程式師花了半個月:把這本書的全部重點都整理好了!超長

起步

《流暢的python》是一本適合python進階的書, 裡面介紹的基本都是高級的python用法. 對於初學python的人來說, 基礎大概也就夠用了, 但往往由於夠用讓他們忘了深入, 去精通. 我們希望全面瞭解這個語言的能力邊界, 可能一些高級的特性並不能馬上掌握使用, 因此這本書是工作之餘, 還有餘力的人來閱讀, 我這邊就將其有用, 精妙的進階內容整理出來.在給大家分享之前呢, 小編推薦一下一個挺不錯的交流寶地, 裡面都是一群熱愛並在學習Python的小夥伴們, 大幾千了吧, 各種各樣的人群都有, 特別喜歡看到這種大家一起交流解決難題的氛圍,

群資料也上傳了好多, 各種大牛解決小白的問題, 這個Python群:330637182 歡迎大家進來一起交流討論, 一起進步, 儘早掌握這門Python語言。

這本書有21個章節, 整理也是根據這些章節過來.

第一章: python資料模型

第二章: 序列構成的陣列

這部分主要是介紹序列, 著重介紹陣列和元組的一些高級用法.

序列按照容納資料的類型可以分為:

容器序列 : list、tuple 和 collections.deque 這些序列能存放不同類型的資料

扁平序列 : str、bytes、bytearray、memoryview 和 array.array, 這類序列只能容納一種類型.

如果按照是否能被修改可以分為:

可變序列 : list、bytearray、array.array、collections.deque 和 memoryview

不可變序列 : tuple、str 和 bytes

列表推導

列表推導是構建清單的快捷方式, 可讀性更好且效率更高.

例如, 把一個字串變成unicode的碼位元列表的例子, 一般:

第三章: 字典和集合

defaultdict:處理找不到的鍵的一個選擇

當某個鍵不在映射裡, 我們也希望也能得到一個預設值. 這就是 defaultdict , 它是 dict 的子類, 並實現了 __missing__ 方法.

不可變映射類型

說到不可變, 第一想到的肯定是元組, 但是對於字典來說, 要將key和value的對應關係變成不可變, types 模組的 MappingPrype 可以做到:

第四章: 文本和位元組序列

本章討論了文本字串和位元組序列, 以及一些編碼上的轉換. 本章討論的 str指的是python3下的.

字元問題

如果字元序列和預期不符, 在進行解碼或編碼時容易拋出 Unicode*Error的異常. 造成這種錯誤是因為目標編碼中沒有定義某個字元(沒有定義某個碼位元對應的字元), 這裡說說解決這類問題的方式.

unicode文本排序

對於字串來說, 比較的碼位. 所以在非 ascii 字元時, 得到的結果可能會不盡人意.

第五章: 一等函數

高階函數

高階函數就是接受函數作為參數, 或者把函數作為返回結果的函數. 如 map , filter , reduce等.

第六章: 使用一等函數實現設計模式

雖然設計模式與語言無關, 但這並不意味著每一個模式都能在每一個語言中使用. Gamma 等人合著的 《設計模式:可複用物件導向軟體的基礎》 一書中有 23 個模式, 其中有 16
個在動態語言中"不見了, 或者簡化了".

這裡不舉例設計模式, 因為書裡的模式不常用.

第七章: 函數裝飾器和閉包

函數裝飾器用於在源碼中“標記”函數,以某種方式增強函數的行為。這是一項強大的功 能,但是若想掌握,必須理解閉包。

修飾器和閉包經常在一起討論, 因為修飾器就是閉包的一種形式. 閉包還是回調式非同步程式設計和函數式程式設計風格的基礎.

裝飾器基礎知識

裝飾器是可調用的物件, 其參數是另一個函數(被裝飾的函數). 裝飾器可能會處理被 裝飾的函數, 然後把它返回, 或者將其替換成另一個函數或可調用物件.

閉包

閉包其實挺好理解的, 當匿名函數出現的時候, 才使得這部分難以掌握. 簡單簡短的解釋閉包就是:

名字空間與函數捆綁後的結果被稱為一個閉包(closure).

如果兩個變數都是指向同一個物件, 我們通常會說變數是另一個變數的 別名 .

在==和is之間選擇運算子 == 是用來判斷兩個物件值是否相等(注意是物件值). 而 is 則是用於判斷兩個變數是否指向同一個物件, 或者說判斷變數是不是兩一個的別名, is 並不關心物件的值. 從使用上, == 使用比較多, 而 is 的執行速度比較快.

函數的參數做引用時

python中的函數參數都是採用共用傳參. 共用傳參指函數的各個形式參數獲得實參中各個引用的副本. 也就是說, 函數內部的形參 是實參的別名.

這種方案就是當傳入參數是可變物件時, 在函數內對參數的修改也就是對外部可變物件進行修改. 但這種參數試圖重新賦值為一個新的物件時則無效, 因為這只是相當於把參數作為另一個東西的引用, 原有的對象並不變. 也就是說, 在函數內, 參數是不能把一個物件替換成另一個物件的.

不要使用可變類型作為參數的預設值

參數預設值是個很棒的特性. 對於開發者來說, 應該避免使用可變物件作為參數預設值. 因為如果參數預設值是可變物件, 而且修改了它的內容, 那麼後續的函式呼叫上都會收到影響.

del和垃圾回收

在python中, 當一個物件失去了最後一個引用時, 會當做垃圾, 然後被回收掉. 雖然python提供了 del 語句用來刪除變數. 但實際上只是刪除了變數和物件之間的引用, 並不一定能讓物件進行回收, 因為這個物件可能還存在其他引用.

在CPython中, 垃圾回收主要用的是引用計數的演算法. 每個物件都會統計有多少引用指向自己. 當引用計數歸零時, 意味著這個物件沒有在使用, 物件就會被立即銷毀.

符合Python風格的物件

得益於 Python 資料模型,自訂類型的行為可以像內置類型那樣自然。實現如此自然的 行為,靠的不是繼承,而是鴨子類型(duck typing):我們只需按照預定行為實現物件所 需的方法即可。

物件表示形式

每門物件導向的語言至少都有一種獲取物件的字串表示形式的標準方式。Python 提供了 兩種方式。

Python中的把使用一個底線首碼標記的屬性稱為"受保護的"屬性

使用slots類屬性節省空間

第十一章: 介面:從協定到抽象基類

這些協定定義為非正式的介面, 是讓程式設計語言實現多態的方式. 在python中, 沒有 interface 關鍵字, 而且除了抽象基類, 每個類都有介面: 所有類都可以自行實現 __getitem__ 和 __add__ .

有寫規定則是程式師在開發過程中慢慢總結出來的, 如受保護的屬性命名採用單個前導底線, 還有一些編碼規範之類的.

協定是介面, 但不是正式的, 這些規定並不是強制性的, 一個類可能只實現部分介面, 這是允許的.

既然有非正式的協議, 那麼有沒有正式的協議呢? 有, 抽象基類就是一種強制性的協議.

抽象基類要求其子類需要實現定義的某個介面, 且抽象基類不能產生實體.

Python文化中的介面和協定

引入抽象基類之前, python就已經非常成功了, 即使現在也很少使用抽象基類. 通過鴨子類型和協定, 我們把協定定義為非正式介面, 是讓python實現多態的方式.

另一邊面, 不要覺得把公開資料屬性放入物件的介面中不妥, 如果需要, 總能實現讀值和設值方法, 把資料屬性變成特性. 物件公開方法的自己, 讓物件在系統中扮演特定的角色. 因此, 介面是實現特定角色的方法集合.

序列協定是python最基礎的協定之一, 即便物件只實現那個協定最基本的一部分, 解譯器也會負責地處理.

水禽和抽象基類

鴨子類型在很多情況下十分有用, 但是隨著發展, 通常由了更好的方式.

近代, 屬和種基本是根據表型系統學分類的, 鴨科屬於水禽, 而水禽還包括鵝, 鴻雁等. 水禽是對某一類表現一致進行的分類, 他們有一些統一"描述"部分.

因此, 根據分類的演化, 需要有個水禽類型, 只要 cls 是抽象基類, 即 cls 的元類是 abc.ABCMeta , 就可以使用 isinstance(obj, cls) 來進行判斷.

與具類相比, 抽象基類有很多理論上的優點, 被註冊的類必須滿足抽象基類對方法和簽名的要求, 更重要的是滿足底層語義契約.

標準庫中的抽象基類

大多數的標準庫的抽象基類在 collections.abc 模組中定義. 少部分在 numbers 和 io 包中有一些抽象基類. 標準庫中有兩個 abc 模組, 這裡只討論 collections.abc .

這個模組中定義了 16 個抽象基類.

Iterable、Container 和 Sized各個集合應該繼承這三個抽象基類,或者至少實現相容的協議。 Iterable 通過 __iter__ 方法支持反覆運算,Container 通過 __contains__ 方法支持 in 運算子,Sized 通過 __len__ 方法支援 len() 函數。

Sequence、Mapping 和 Set這三個是主要的不可變集合類型,而且各自都有可變的子類。

MappingView在 Python3 中,映射方法 .items() 、 .keys() 和 .values() 返回的物件分別是 ItemsView、KeysView 和 ValuesView 的實例。前兩個類還從 Set 類繼承了豐富的接 口。

Callable 和 Hashable這兩個抽象基類與集合沒有太大的關係,只不過因為 collections.abc是標準庫中 定義抽象基類的第一個模組,而它們又太重要了,因此才把它們放到 collections.abc 模組中。我從未見過 Callable 或 Hashable 的子類。這兩個抽象基類的主要作用是為內 置函數 isinstance 提供支援,以一種安全的方式判斷物件能不能調用或散列。

Iterator注意它是 Iterable 的子類。

第十二章: 繼承的優缺點

很多人覺得多重繼承得不償失, 那些不支援多繼承的程式設計語言好像也沒什麼損失.

子類化內置類型很麻煩

python2.2 以前, 內置類型(如list, dict)是不能子類化的. 它們是不能被其他類所繼承的, 原因是內置類型是C語言實現的, 不會調用用戶定義的類覆蓋的方法.

至於內置類型的子類覆蓋的方法會不會隱式調用, CPython 官方也沒有制定規則. 基本上, 內置類型的方法不會調用子類覆蓋的方法. 例如, dict 的子類覆蓋的 __getitem__ 方法不會覆蓋內置類型的 get() 方法調用.

多重繼承和方法解析順序

任何實現多重繼承的語言都要處理潛在的命名衝突,這種衝突由不相關的祖先類實現同名 方法引起。這種衝突稱為“菱形問題”,如圖.

Python 會按照特定的順序遍歷繼承 圖。這個順序叫方法解析順序(Method Resolution Order,MRO)。類都有一個名為 mro 的屬性,它的值是一個元組,按照方法解析順序列出各個超類,從當前類一直 向上,直到 object 類。

第十三章: 正確重載運算子

在python中, 大多數的運算子是可以重載的, 如 == 對應了 __eq__ , + 對應 __add__ .

某些運算子不能重載, 如 is, and, or, and .

第十四章: 可反覆運算的對象、反覆運算器和生成器

反覆運算是資料處理的基石. 掃描記憶體中放不下的資料集時, 我們要找到一種惰性獲取資料的方式, 即按需一次獲取一個資料. 這就是 反覆運算器模式 .

python中有 yield 關鍵字, 用於構建 生成器(generator) , 其作用用於反覆運算器一樣.

所有的生成器都是反覆運算器, 因為生成器完全實現了反覆運算器的介面.

檢查物件 x 是否反覆運算, 最準確的方法是調用 iter(x) , 如果不可反覆運算, 則拋出 TypeError 異常. 這個方法比 isinstance(x, abc.Iterable) 更準確, 因為它還考慮到遺留的 __getitem__ 方法.

可反覆運算的物件與反覆運算器的對比

我們需要對可反覆運算的物件進行一下定義:

使用 iter 內置函數可以獲取反覆運算器的物件。如果物件實現了能返回反覆運算器的 iter 方法,那麼物件就是可反覆運算的。序列都可以反覆運算;實現了 getitem 方 法,而且其參數是從零開始的索引,這種物件也可以反覆運算。

我們要明確可反覆運算物件和反覆運算器之間的關係: 從可反覆運算的對象中獲取反覆運算器.

標準的反覆運算器介面有兩個方法:

__next__ : 返回下一個可用的元素, 如果沒有元素了, 拋出 StopIteration 異常.

__iter__ : 返回 self , 以便咋應該使用可反覆運算物件的地方使用反覆運算器.

典型的反覆運算器

為了清楚地說明可反覆運算物件與反覆運算器之間的重要區別, 我們將兩者分開, 寫成兩個類:

這個例子主要是為了區分可反覆運算對象和反覆運算器, 這種情況工作量一般比較大, 程式師也不願這樣寫.

生成器運算式

生成器運算式可以理解為列表推導的惰性版本: 不會迫切地構建列表, 而是返回一個生成器, 按需惰性生成元素. 也就是, 如果列表推導是產出列表的工廠, 那麼生成器運算式就是產出生成器的工廠.

標準庫中的生成器函數

用於映射的生成器函數

模組函數說明itertoolsaccumulate(it, [func])產出累積的總和;如果提供了 func,那麼把前兩個元素傳給它,然後把計算結果和下一個元素傳給它,以此類推,最後產出結果(內置)enumerate(iterable, start=0)產出由兩個元素組成的元組,結構是 (index, item),其中 index 從 start 開始計數,item 則從 iterable 中獲取(內置)map(func, it1, [it2, ..., itN])把 it 中的各個元素傳給func,產出結果;如果傳入 N 個可反覆運算的物件,那麼 func 必須能接受 N 個參數,而且要並行處理各個可反覆運算的物件

合併多個可反覆運算物件的生成器函數

模組函數說明itertoolschain(it1, ..., itN)先產出 it1 中的所有元素,然後產出 it2 中的所有元素,以此類推,無縫連接在一起itertoolschain.from_iterable(it)產出 it 生成的各個可反覆運算物件中的元素,一個接一個,無縫連接在一起;it 應該產出可反覆運算的元素,例如可反覆運算的對象清單(內置)zip(it1, ..., itN)並行從輸入的各個可反覆運算物件中獲取元素,產出由 N 個元素組成的元組,只要有一個可反覆運算的物件到頭了,就默默地停止

新的句法:yield from

如果生成器函數需要產出另一個生成器生成的值, 傳統的方式是嵌套的 for 迴圈, 例如, 我們要自己實現 chain生成器:

可反覆運算的歸約函數

有些函數接受可反覆運算物件, 但僅返回單個結果, 這類函數叫規約函數.

模組函數說明(內置)sum(it, start=0)it 中所有元素的總和,如果提供可選的 start,會把它加上(計算浮點數的加法時,可以使用 math.fsum 函數提高精度)(內置)all(it)it 中的所有元素都為真值時返回 True,否則返回 False;all([]) 返回 True(內置)any(it)只要 it 中有元素為真值就返回 True,否則返回 False;any([]) 返回 False(內置)max(it, [key=,] [default=])返回 it 中值最大的元素;*key 是排序函數,與 sorted 函數中的一樣;如果可反覆運算的物件為空,返回 defaultfunctoolsreduce(func, it, [initial])把前兩個元素傳給 func,然後把計算結果和第三個元素傳給 func,以此類推,返回最後的結果;如果提供了 initial,把它當作第一個元素傳入

第十五章: 上下文管理器和 else 塊

本章討論的是其他語言不常見的流程控制特性, 正因如此, python新手往往忽視或沒有充分使用這些特性. 下面討論的特性有:

with 語句和上下文管理器

for while try 語句的 else 子句

上下文管理器和with塊

使用@contextmanager

第十六章: 協程

預激協程的裝飾器

協程內部如果不能處理這個異常, 就會導致協程終止.

第十七章: 使用期物處理併發

第十八章: 使用 asyncio 包處理併發

併發是指一次處理多件事。 並行是指一次做多件事。 二者不同,但是有聯繫。 一個關於結構,一個關於執行。 併發用於制定方案,用來解決可能(但未必)並行的問題。—— Rob Pike Go 語言的創造者之一

並行是指兩個或者多個事件在同一時刻發生, 而併發是指兩個或多個事件在同一時間間隔發生. 真正運行並行需要多個核心, 現在筆記本一般有 4 個 CPU 核心, 但是通常就有超過 100 個進程同時運行. 因此, 實際上大多數進程都是併發處理的, 而不是並行處理. 電腦始終運行著 100 多個進程, 確保每個進程都有機會取得發展, 不過 CPU 本身同時做的事情不會超過四件.

從期物、任務和協程中產出

避免阻塞型調用

有兩種方法能避免阻塞型調用中止整個應用程式的進程:

在單獨的執行緒中運行各個阻塞型操作

把每個阻塞型操作轉換成非阻塞的非同步調用使用

多執行緒是可以的, 但是會消耗比較大的記憶體. 為了降低記憶體的消耗, 通常使用回檔來實現非同步調用. 這是一種底層概念, 類似所有併發機制中最古老最原始的那種--硬體中斷. 使用回檔時, 我們不等待響應, 而是註冊一個函數, 在發生某件事時調用. 這樣, 所有的調用都是非阻塞的.

非同步應用程式底層的事件迴圈能依靠基礎設置的中斷, 執行緒, 輪詢和後臺進程等待等, 確保多個併發請求能取得進展並最終完成, 這樣才能使用回檔. 事件迴圈獲得響應後, 會回過頭來調用我們指定的回檔. 如果做法正確, 事件迴圈和應用代碼公共的主執行緒絕不會阻塞.

把生成器當做協程使用是非同步程式設計的另一種方式. 對事件迴圈來說, 調用回檔與在暫停的協程上調用 .send() 效果差不多.

覆蓋型與非覆蓋型描述符對比

python存取屬性的方式是不對等的. 通過實例讀取屬性時, 通常返回的是實例中定義的屬性, 但是, 如果實例中沒有指定的屬性, 那麼會從獲取類屬性. 而實例中屬性賦值時, 通常會在實例中創建屬性, 根本不影響類.

覆蓋型描述符

我們要做一個在運行時創建類的, 類工廠函數:

元類基礎知識

元類是製造類的工廠, 不過不是函數, 本身也是類. 元類是用於構建類的類 .

謝謝大家閱讀,謝謝“棲遲於一丘”的分享!超牛逼!原文連結

如有侵權請聯繫小編刪除!

第四章: 文本和位元組序列

本章討論了文本字串和位元組序列, 以及一些編碼上的轉換. 本章討論的 str指的是python3下的.

字元問題

如果字元序列和預期不符, 在進行解碼或編碼時容易拋出 Unicode*Error的異常. 造成這種錯誤是因為目標編碼中沒有定義某個字元(沒有定義某個碼位元對應的字元), 這裡說說解決這類問題的方式.

unicode文本排序

對於字串來說, 比較的碼位. 所以在非 ascii 字元時, 得到的結果可能會不盡人意.

第五章: 一等函數

高階函數

高階函數就是接受函數作為參數, 或者把函數作為返回結果的函數. 如 map , filter , reduce等.

第六章: 使用一等函數實現設計模式

雖然設計模式與語言無關, 但這並不意味著每一個模式都能在每一個語言中使用. Gamma 等人合著的 《設計模式:可複用物件導向軟體的基礎》 一書中有 23 個模式, 其中有 16
個在動態語言中"不見了, 或者簡化了".

這裡不舉例設計模式, 因為書裡的模式不常用.

第七章: 函數裝飾器和閉包

函數裝飾器用於在源碼中“標記”函數,以某種方式增強函數的行為。這是一項強大的功 能,但是若想掌握,必須理解閉包。

修飾器和閉包經常在一起討論, 因為修飾器就是閉包的一種形式. 閉包還是回調式非同步程式設計和函數式程式設計風格的基礎.

裝飾器基礎知識

裝飾器是可調用的物件, 其參數是另一個函數(被裝飾的函數). 裝飾器可能會處理被 裝飾的函數, 然後把它返回, 或者將其替換成另一個函數或可調用物件.

閉包

閉包其實挺好理解的, 當匿名函數出現的時候, 才使得這部分難以掌握. 簡單簡短的解釋閉包就是:

名字空間與函數捆綁後的結果被稱為一個閉包(closure).

如果兩個變數都是指向同一個物件, 我們通常會說變數是另一個變數的 別名 .

在==和is之間選擇運算子 == 是用來判斷兩個物件值是否相等(注意是物件值). 而 is 則是用於判斷兩個變數是否指向同一個物件, 或者說判斷變數是不是兩一個的別名, is 並不關心物件的值. 從使用上, == 使用比較多, 而 is 的執行速度比較快.

函數的參數做引用時

python中的函數參數都是採用共用傳參. 共用傳參指函數的各個形式參數獲得實參中各個引用的副本. 也就是說, 函數內部的形參 是實參的別名.

這種方案就是當傳入參數是可變物件時, 在函數內對參數的修改也就是對外部可變物件進行修改. 但這種參數試圖重新賦值為一個新的物件時則無效, 因為這只是相當於把參數作為另一個東西的引用, 原有的對象並不變. 也就是說, 在函數內, 參數是不能把一個物件替換成另一個物件的.

不要使用可變類型作為參數的預設值

參數預設值是個很棒的特性. 對於開發者來說, 應該避免使用可變物件作為參數預設值. 因為如果參數預設值是可變物件, 而且修改了它的內容, 那麼後續的函式呼叫上都會收到影響.

del和垃圾回收

在python中, 當一個物件失去了最後一個引用時, 會當做垃圾, 然後被回收掉. 雖然python提供了 del 語句用來刪除變數. 但實際上只是刪除了變數和物件之間的引用, 並不一定能讓物件進行回收, 因為這個物件可能還存在其他引用.

在CPython中, 垃圾回收主要用的是引用計數的演算法. 每個物件都會統計有多少引用指向自己. 當引用計數歸零時, 意味著這個物件沒有在使用, 物件就會被立即銷毀.

符合Python風格的物件

得益於 Python 資料模型,自訂類型的行為可以像內置類型那樣自然。實現如此自然的 行為,靠的不是繼承,而是鴨子類型(duck typing):我們只需按照預定行為實現物件所 需的方法即可。

物件表示形式

每門物件導向的語言至少都有一種獲取物件的字串表示形式的標準方式。Python 提供了 兩種方式。

Python中的把使用一個底線首碼標記的屬性稱為"受保護的"屬性

使用slots類屬性節省空間

第十一章: 介面:從協定到抽象基類

這些協定定義為非正式的介面, 是讓程式設計語言實現多態的方式. 在python中, 沒有 interface 關鍵字, 而且除了抽象基類, 每個類都有介面: 所有類都可以自行實現 __getitem__ 和 __add__ .

有寫規定則是程式師在開發過程中慢慢總結出來的, 如受保護的屬性命名採用單個前導底線, 還有一些編碼規範之類的.

協定是介面, 但不是正式的, 這些規定並不是強制性的, 一個類可能只實現部分介面, 這是允許的.

既然有非正式的協議, 那麼有沒有正式的協議呢? 有, 抽象基類就是一種強制性的協議.

抽象基類要求其子類需要實現定義的某個介面, 且抽象基類不能產生實體.

Python文化中的介面和協定

引入抽象基類之前, python就已經非常成功了, 即使現在也很少使用抽象基類. 通過鴨子類型和協定, 我們把協定定義為非正式介面, 是讓python實現多態的方式.

另一邊面, 不要覺得把公開資料屬性放入物件的介面中不妥, 如果需要, 總能實現讀值和設值方法, 把資料屬性變成特性. 物件公開方法的自己, 讓物件在系統中扮演特定的角色. 因此, 介面是實現特定角色的方法集合.

序列協定是python最基礎的協定之一, 即便物件只實現那個協定最基本的一部分, 解譯器也會負責地處理.

水禽和抽象基類

鴨子類型在很多情況下十分有用, 但是隨著發展, 通常由了更好的方式.

近代, 屬和種基本是根據表型系統學分類的, 鴨科屬於水禽, 而水禽還包括鵝, 鴻雁等. 水禽是對某一類表現一致進行的分類, 他們有一些統一"描述"部分.

因此, 根據分類的演化, 需要有個水禽類型, 只要 cls 是抽象基類, 即 cls 的元類是 abc.ABCMeta , 就可以使用 isinstance(obj, cls) 來進行判斷.

與具類相比, 抽象基類有很多理論上的優點, 被註冊的類必須滿足抽象基類對方法和簽名的要求, 更重要的是滿足底層語義契約.

標準庫中的抽象基類

大多數的標準庫的抽象基類在 collections.abc 模組中定義. 少部分在 numbers 和 io 包中有一些抽象基類. 標準庫中有兩個 abc 模組, 這裡只討論 collections.abc .

這個模組中定義了 16 個抽象基類.

Iterable、Container 和 Sized各個集合應該繼承這三個抽象基類,或者至少實現相容的協議。 Iterable 通過 __iter__ 方法支持反覆運算,Container 通過 __contains__ 方法支持 in 運算子,Sized 通過 __len__ 方法支援 len() 函數。

Sequence、Mapping 和 Set這三個是主要的不可變集合類型,而且各自都有可變的子類。

MappingView在 Python3 中,映射方法 .items() 、 .keys() 和 .values() 返回的物件分別是 ItemsView、KeysView 和 ValuesView 的實例。前兩個類還從 Set 類繼承了豐富的接 口。

Callable 和 Hashable這兩個抽象基類與集合沒有太大的關係,只不過因為 collections.abc是標準庫中 定義抽象基類的第一個模組,而它們又太重要了,因此才把它們放到 collections.abc 模組中。我從未見過 Callable 或 Hashable 的子類。這兩個抽象基類的主要作用是為內 置函數 isinstance 提供支援,以一種安全的方式判斷物件能不能調用或散列。

Iterator注意它是 Iterable 的子類。

第十二章: 繼承的優缺點

很多人覺得多重繼承得不償失, 那些不支援多繼承的程式設計語言好像也沒什麼損失.

子類化內置類型很麻煩

python2.2 以前, 內置類型(如list, dict)是不能子類化的. 它們是不能被其他類所繼承的, 原因是內置類型是C語言實現的, 不會調用用戶定義的類覆蓋的方法.

至於內置類型的子類覆蓋的方法會不會隱式調用, CPython 官方也沒有制定規則. 基本上, 內置類型的方法不會調用子類覆蓋的方法. 例如, dict 的子類覆蓋的 __getitem__ 方法不會覆蓋內置類型的 get() 方法調用.

多重繼承和方法解析順序

任何實現多重繼承的語言都要處理潛在的命名衝突,這種衝突由不相關的祖先類實現同名 方法引起。這種衝突稱為“菱形問題”,如圖.

Python 會按照特定的順序遍歷繼承 圖。這個順序叫方法解析順序(Method Resolution Order,MRO)。類都有一個名為 mro 的屬性,它的值是一個元組,按照方法解析順序列出各個超類,從當前類一直 向上,直到 object 類。

第十三章: 正確重載運算子

在python中, 大多數的運算子是可以重載的, 如 == 對應了 __eq__ , + 對應 __add__ .

某些運算子不能重載, 如 is, and, or, and .

第十四章: 可反覆運算的對象、反覆運算器和生成器

反覆運算是資料處理的基石. 掃描記憶體中放不下的資料集時, 我們要找到一種惰性獲取資料的方式, 即按需一次獲取一個資料. 這就是 反覆運算器模式 .

python中有 yield 關鍵字, 用於構建 生成器(generator) , 其作用用於反覆運算器一樣.

所有的生成器都是反覆運算器, 因為生成器完全實現了反覆運算器的介面.

檢查物件 x 是否反覆運算, 最準確的方法是調用 iter(x) , 如果不可反覆運算, 則拋出 TypeError 異常. 這個方法比 isinstance(x, abc.Iterable) 更準確, 因為它還考慮到遺留的 __getitem__ 方法.

可反覆運算的物件與反覆運算器的對比

我們需要對可反覆運算的物件進行一下定義:

使用 iter 內置函數可以獲取反覆運算器的物件。如果物件實現了能返回反覆運算器的 iter 方法,那麼物件就是可反覆運算的。序列都可以反覆運算;實現了 getitem 方 法,而且其參數是從零開始的索引,這種物件也可以反覆運算。

我們要明確可反覆運算物件和反覆運算器之間的關係: 從可反覆運算的對象中獲取反覆運算器.

標準的反覆運算器介面有兩個方法:

__next__ : 返回下一個可用的元素, 如果沒有元素了, 拋出 StopIteration 異常.

__iter__ : 返回 self , 以便咋應該使用可反覆運算物件的地方使用反覆運算器.

典型的反覆運算器

為了清楚地說明可反覆運算物件與反覆運算器之間的重要區別, 我們將兩者分開, 寫成兩個類:

這個例子主要是為了區分可反覆運算對象和反覆運算器, 這種情況工作量一般比較大, 程式師也不願這樣寫.

生成器運算式

生成器運算式可以理解為列表推導的惰性版本: 不會迫切地構建列表, 而是返回一個生成器, 按需惰性生成元素. 也就是, 如果列表推導是產出列表的工廠, 那麼生成器運算式就是產出生成器的工廠.

標準庫中的生成器函數

用於映射的生成器函數

模組函數說明itertoolsaccumulate(it, [func])產出累積的總和;如果提供了 func,那麼把前兩個元素傳給它,然後把計算結果和下一個元素傳給它,以此類推,最後產出結果(內置)enumerate(iterable, start=0)產出由兩個元素組成的元組,結構是 (index, item),其中 index 從 start 開始計數,item 則從 iterable 中獲取(內置)map(func, it1, [it2, ..., itN])把 it 中的各個元素傳給func,產出結果;如果傳入 N 個可反覆運算的物件,那麼 func 必須能接受 N 個參數,而且要並行處理各個可反覆運算的物件

合併多個可反覆運算物件的生成器函數

模組函數說明itertoolschain(it1, ..., itN)先產出 it1 中的所有元素,然後產出 it2 中的所有元素,以此類推,無縫連接在一起itertoolschain.from_iterable(it)產出 it 生成的各個可反覆運算物件中的元素,一個接一個,無縫連接在一起;it 應該產出可反覆運算的元素,例如可反覆運算的對象清單(內置)zip(it1, ..., itN)並行從輸入的各個可反覆運算物件中獲取元素,產出由 N 個元素組成的元組,只要有一個可反覆運算的物件到頭了,就默默地停止

新的句法:yield from

如果生成器函數需要產出另一個生成器生成的值, 傳統的方式是嵌套的 for 迴圈, 例如, 我們要自己實現 chain生成器:

可反覆運算的歸約函數

有些函數接受可反覆運算物件, 但僅返回單個結果, 這類函數叫規約函數.

模組函數說明(內置)sum(it, start=0)it 中所有元素的總和,如果提供可選的 start,會把它加上(計算浮點數的加法時,可以使用 math.fsum 函數提高精度)(內置)all(it)it 中的所有元素都為真值時返回 True,否則返回 False;all([]) 返回 True(內置)any(it)只要 it 中有元素為真值就返回 True,否則返回 False;any([]) 返回 False(內置)max(it, [key=,] [default=])返回 it 中值最大的元素;*key 是排序函數,與 sorted 函數中的一樣;如果可反覆運算的物件為空,返回 defaultfunctoolsreduce(func, it, [initial])把前兩個元素傳給 func,然後把計算結果和第三個元素傳給 func,以此類推,返回最後的結果;如果提供了 initial,把它當作第一個元素傳入

第十五章: 上下文管理器和 else 塊

本章討論的是其他語言不常見的流程控制特性, 正因如此, python新手往往忽視或沒有充分使用這些特性. 下面討論的特性有:

with 語句和上下文管理器

for while try 語句的 else 子句

上下文管理器和with塊

使用@contextmanager

第十六章: 協程

預激協程的裝飾器

協程內部如果不能處理這個異常, 就會導致協程終止.

第十七章: 使用期物處理併發

第十八章: 使用 asyncio 包處理併發

併發是指一次處理多件事。 並行是指一次做多件事。 二者不同,但是有聯繫。 一個關於結構,一個關於執行。 併發用於制定方案,用來解決可能(但未必)並行的問題。—— Rob Pike Go 語言的創造者之一

並行是指兩個或者多個事件在同一時刻發生, 而併發是指兩個或多個事件在同一時間間隔發生. 真正運行並行需要多個核心, 現在筆記本一般有 4 個 CPU 核心, 但是通常就有超過 100 個進程同時運行. 因此, 實際上大多數進程都是併發處理的, 而不是並行處理. 電腦始終運行著 100 多個進程, 確保每個進程都有機會取得發展, 不過 CPU 本身同時做的事情不會超過四件.

從期物、任務和協程中產出

避免阻塞型調用

有兩種方法能避免阻塞型調用中止整個應用程式的進程:

在單獨的執行緒中運行各個阻塞型操作

把每個阻塞型操作轉換成非阻塞的非同步調用使用

多執行緒是可以的, 但是會消耗比較大的記憶體. 為了降低記憶體的消耗, 通常使用回檔來實現非同步調用. 這是一種底層概念, 類似所有併發機制中最古老最原始的那種--硬體中斷. 使用回檔時, 我們不等待響應, 而是註冊一個函數, 在發生某件事時調用. 這樣, 所有的調用都是非阻塞的.

非同步應用程式底層的事件迴圈能依靠基礎設置的中斷, 執行緒, 輪詢和後臺進程等待等, 確保多個併發請求能取得進展並最終完成, 這樣才能使用回檔. 事件迴圈獲得響應後, 會回過頭來調用我們指定的回檔. 如果做法正確, 事件迴圈和應用代碼公共的主執行緒絕不會阻塞.

把生成器當做協程使用是非同步程式設計的另一種方式. 對事件迴圈來說, 調用回檔與在暫停的協程上調用 .send() 效果差不多.

覆蓋型與非覆蓋型描述符對比

python存取屬性的方式是不對等的. 通過實例讀取屬性時, 通常返回的是實例中定義的屬性, 但是, 如果實例中沒有指定的屬性, 那麼會從獲取類屬性. 而實例中屬性賦值時, 通常會在實例中創建屬性, 根本不影響類.

覆蓋型描述符

我們要做一個在運行時創建類的, 類工廠函數:

元類基礎知識

元類是製造類的工廠, 不過不是函數, 本身也是類. 元類是用於構建類的類 .

謝謝大家閱讀,謝謝“棲遲於一丘”的分享!超牛逼!原文連結

如有侵權請聯繫小編刪除!

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示