1. 程式人生 > >筆記之《Python學習手冊》第4版

筆記之《Python學習手冊》第4版

Learning Python

(4th Edition

Python學習手冊

第4版

Mark Lutz著

李軍 劉紅偉等譯

O’REILLY Media, Inc

機械工業出版社

其實,我原先是不準備做這個筆記的,感覺程式設計這是技術性問題,多練即可,無奈大腦記性不佳,且技術之間的關係又沒有搞清楚,故特作此筆記,以圖理清脈絡,加強記憶。

這篇筆記不會像以前那樣詳細,只是作為個人一種梳理、助記工具而已。

話說該作者挺為初學者著想的,全面詳細,美中不足的是話有些重複。

一個多星期讀完這本書,我好佩服自己啊!!!

型別和運算

  1. 程式由模組構成。
  2. 模組包含語句。
  3. 語句包含表示式。
  4. 表示式建立並處理物件。

核心資料型別

數字

字串

列表

字典

字典檢視

元組

檔案

集合

動態型別

變數在賦值是建立,可以引用任何型別的物件,並且必須在引用之前賦值

變數是一個系統表的元素擁有指向物件的連線的空間

物件是分配的一塊記憶體有足夠的空間去表示它們代表的值

引用是自動形成的從變數到物件的指標

型別屬於物件其頭部有一個型別識別符號和一個引用計數器

引用計數器為零時,該物件的記憶體空間會被回收。

作為一種優化Python會快取不變的物件通常是小的整數和小的字串並對其複用

共享引用——多個變數名引用了同一個物件。當物件是不變物件時,修改其中一個變數不會影響到另外一個,但物件是可變物件時,原處修改則會影響到。

內建型別陷阱

賦值產生引用,而不是拷貝

重複能夠增加層次深度

留意迴圈資料結構

不可變型別不可以在原處改變

語句和語法

賦值表示式和列印

賦值

賦值語句執行時,python會建立相應的臨時資料型別儲存右側變數原始的值

Python 3.0中的擴充套件序列解包,*號會使變數匹配剩下的內容

If測試和語法規則

布林運算時,有短路規則,返回的是短路時所測試的物件。

While和for迴圈

迴圈else語句用於非break語句跳出,注意其縮排。

內建的range函式返回一系列連續增加的整數可作為for中的索引

zip函式返回並行元素的元祖列表可用於for中遍歷數個序列

enumerate函式產生偏移值及偏移值處的值

迭代器和解析,第一部分

一般情況下,“可迭代的”指支援iter的一個物件,“迭代器”值iter所返回的一個支援next(I)的物件

for迴圈開始時會通過它傳給iter內建函式以便從中取得迭代器

列表解析從語法上講源於集合理論表示法中的一個結構難道是我在高中學的那個】。通常其迭代是以C語言的速度執行

文件

#註釋

dir函式

文件字串:__doc__

寫成字串,放在模組檔案、函式以及類語句的頂端的註釋

PyDoc:help函式

提取文件字串並且自動提取其結構化的資訊,並將其格式化成各種型別的排列友好的報表。

PyDoc:HTML報表

函式

函式基礎

def語句是實時執行的

作用域

作用域法則

內嵌的模組是全域性作用域。

全域性作用域的作用範圍僅限於單個檔案

每次對函式的呼叫都建立一個新的本地作用域

賦值的變數名除非宣告為全域性或非本地否則均為本地

所有其他的變數名都快歸納為本地全域性或內建的

變數名解析:LEGB原則

當在函式中使用為認證的變數名時,會搜尋4個作用域,本地(L),上層函式的本地(E),全域性(G),內建(B,__builtin__標準庫模組),在第一個找到處停下。

當在函式中給一個變數名賦值時Python總是建立或改變本地的變數名除非已經宣告為全域性變數

在函式外給變數名賦值時,本地與全域性是相同的。

global語句

全域性變數如果在函式內被賦值的話,必須經過global宣告

全域性變數名在函式內部不經過宣告也可被引用

作用域和巢狀函式

巢狀函式能夠記住巢狀作用域的變數值,即使上層函式已經返回了。

nonlocal語句

將變數對映到上層函式作用域中的對應變數。

引數

在函式呼叫中,引數必去以此順序出現:任何位置引數(value),後面跟著任何關鍵字引數(name=value)和*sequence形式的組合,後面跟著**dict形式。

在函式頭部引數必須以此順序出現任何一般引數name),緊跟著任何預設引數(name=value),如果有的話,後面是*name的形式,後面跟著name或name=value keyword-only引數後面跟著**name形式

引數匹配步驟

  1. 通過位置分配非關鍵字引數
  2. 通過匹配變數名分配關鍵字引數
  3. 其他額外的非關鍵字引數分配到*name元祖中
  4. 其他額外的關鍵字引數分配到**name字典中
  5. 用預設值分配給在頭部未得到分配的引數

函式的高階話題

儘量用迴圈,而不是遞迴,因為for迴圈會自動迭代。

函式註解編寫在def頭部行引數註解,引數列表->註解。

匿名函式lambda

是一個表示式,不是一個語句。

主體是一個單個的表示式不是程式碼塊

迭代和解析,第二部分

列表解析通用結構 [expression for target1 in iterable1 [if condtion1] for target2 in iterable2 [if condition2]…]

重訪迭代器生成器

生成器函式:編寫為常規的def語句,但使用yield語句一次返回一個結果,在每個結果之間掛起和繼續他們的狀態。yield語句編譯為生成器呼叫時返回一個支援自動建立__init__方法的迭代器

生成器表示式類似於列表解析返回按需產生結果的一個物件。括在圓括號中而不是方括號中。

模組

模組:巨集偉藍圖

import如何工作

第一次匯入指定檔案時,會執行三個步驟。1、找到模組檔案。2、編譯成位碼(需要時)。3、執行模組的程式碼來建立所定義的物件。

模組搜尋路徑

sys.path包括四個部分

  1. 程式的主目錄
  2. PYTHONPATH目錄
  3. 標準連結庫目錄
  4. 任何.pth檔案的目錄

模組程式碼編寫基礎

import和from是賦值語句

import將整個模組物件賦給一個變數名

from將一個或多個變數名賦給另一模組中同名的物件

匯入和作用域

函式絕對無法看見其他函式內的變數名,除非它在處於這個函式內

模組程式程式碼絕對無法看見其他模組內的變數名除非明確地進行了匯入

過載模組

reload函式強制已載入的模組程式碼重新載入並重新執行。新的程式碼的賦值語句會在適當的地方修改現有的模組物件。

模組包

Python程式碼的目錄稱為包

包和搜尋路徑設定

包所在的容器目錄應在模組搜尋路徑中

__init__.py包檔案

包匯入路徑中的每個目錄內都必須有__init__.py檔案

包首次匯入時會自動執行該檔案

可為目錄所建立的模組物件提供名稱空間包含所賦值的所有變數名

使用__all__列表,定義目錄以from*語句形式匯入時,需要匯出什麼。

包相對匯入

Python 3.0中的變化

修改了模組匯入搜尋路徑語義,以預設地跳過包自己的目錄。到如只是檢查搜尋路徑的其他元件。這叫做“絕對”匯入。

擴充套件了from語句的語法以允許顯式地要求匯入值搜尋包的目錄。這叫做“相對”匯入。

高階模組話題

最小化from*的破壞:_X和__all__

_X會阻止from*匯入此變數名

__all__列表列出了from*語句要匯出的變數

Import語句和from語句的as擴充套件

若要過載from語句匯入的變數需先過載該模組(若該模組沒有匯入的話,需先匯入,再過載),再重新執行from語句。

類和OOP

類程式碼編寫基礎

類產生多個例項物件

類物件提供預設行為

Class語句建立類物件並將其賦值給變數名

Class語句的賦值語句會建立類的屬性

類屬性提供物件的狀態和行為

例項物件是具體的元素

像函式那樣呼叫類物件會建立新的例項物件

每個例項物件繼承類的屬性並獲得了自己的名稱空間

在方法內對self屬性做賦值運算會產生每個例項自己的屬性

類通過繼承進行定製

超類列在了類開頭的括號中

類從其超類中繼承屬性

例項會繼承所有可讀取類的屬性

每個object.attribute都會開啟新的獨立搜尋

邏輯的修改是通過建立子類而不是修改超類

類可以截獲Python運算子

以雙下劃線命名的方法(__X__)是特殊鉤子

當例項出現在內建運算時這類方法會自動呼叫

類可覆蓋多數內建型別運算

運算子覆蓋方法沒有預設值而且也不需要

運算子可讓Python的物件模型相整合

更多例項

步驟1:建立例項

編寫建構函式

以兩種方式使用程式碼作為模組檔案或作為指令碼使用__name__執行測試程式碼

步驟2:新增行為方法

編寫方法

封裝,把操作邏輯包裝到介面之和

步驟3;運算子過載

提供列印顯示

步驟4:通過子類定製行為

編寫子類

擴充套件方法,呼叫超類的方法

繼承、定製和擴充套件

步驟5:定製建構函式

步驟6:使用內省工具

instance.__class__

object.__dict__

步驟7:把物件儲存到資料庫中

Pickle和Shelve

pickle:任意Python物件和位元組串之間的序列化

dbm實現一個可通過鍵訪問的檔案系統以儲存字串

shelve使用另外兩個模組按照鍵把Python物件儲存到一個檔案中

類程式碼編寫細節

運算子過載

建構函式和表示式:__init__和__sub__

索引和分片:__getitem__和__setitem__

攔截分片slice()

索引迭代:__getitem__

迭代器物件:__iter__和__next__

所有迭代環境會先嚐試__iter__方法,再嘗試__getitem__方法。

當迭代器返回自身時只支援一個活躍的迭代器。反之,則可支援獨立位置的多個活躍迭代器。

成員關係:__contains__、__iter__和__getitem__

優先順序如上所示

屬性引用:__getattr__和__setattr__

__getattr__攔截未定義的屬性

__repr__和__str__會返回字串表達形式

列印操作首先嚐試__str__和str內建函式

右側加法和原處加法:__radd__和__iadd__

只有+右側物件是類例項,左側不是時,才呼叫__radd__,其他所有情況下,由左側物件呼叫__add__方法。

Call表示式:__call__

當呼叫例項時,使用該方法。

比較:__It__、__gt__和其他方法

布林測試:__bool__和__len__

物件解構函式:__del__

類的設計

Python的OOP可概括三個概念:繼承、多型和封裝

應該吧程式程式碼寫成預期的物件介面而不是特定的資料型別

OOP和繼承:“是一個”關係

OOP和組合:“有一個”關係

OOP和委託:“包裝”物件

類的偽私有屬性

Class語句中開頭有兩個下劃線,但結尾沒有兩個下劃線的變數名自動擴張,_classname__x

方法是物件:繫結或無繫結

無繫結類方法物件:無self。通過對類進行點號運算從而獲取類的函式屬性。Python 3.0刪除了該概念。

繫結例項方法物件self+函式對通過對例項進行全運算從而獲取類的函式屬性

多重繼承:“混合”類

超類多於一個時,即為多重繼承

傳統類中屬性搜尋深度優先

新式類(以及Python 3.0的所有類),屬性搜尋沿著樹層次廣度優先

__dict__列出例項屬性

用dir列出繼承的屬性

類的高階主題

擴充套件內建型別

通過嵌入擴充套件型別

通過子類擴充套件型別

新式類

(Python 3.0)所有類的繼承自object,所有物件都是object的例項

新式類變化

類和型別合併

繼承搜尋順序

針對內建函式的屬性獲取

新的高階工具

__slots__:只有其列表中的變數名可賦值為例項屬性

異常和工具

異常基礎

異常編碼細節

try/except/else語句

try下的程式碼代表主要動作except定義異常的處理器else子句提供無異常時的處理器

空的except子句捕捉一切異常,捕捉Exception的異常類似於此,但會忽略和系統退出有關的異常。

一旦捕捉了錯誤控制權會在捕捉的地方繼續下去,即try語句之下,沒有直接的方式可以回到異常發生的地方

try/finally語句

當控制權離開try程式碼塊時,Python先執行finally程式碼塊,然後才跳出。finally不會終止異常

統一try/except/finally語句

raise語句

raise <instance>

raise <class>#Make and raise instance of class

raise 重新引發最近引發的異常以傳播已經捕獲的異常

Python 3.0異常鏈raise from

assert語句(斷言)

with/as環境管理器

with expression [as variable]: with-block

expression返回一個支援環境管理器協議(有__enter__和__exit__方法)的物件。其__enter__方法的返回值會賦值給variable

若有異常被引發,__exit__(type,value,traceback)方法被呼叫,若其返回值為假,異常會重新引發,以傳播到with語句外。

沒有異常時,__exit__(None,None,None)會被呼叫。

異常物件

基於類的異常的特點:提供型別分類;附件狀態資訊;支援繼承。

異常的設計

巢狀異常處理器

關於sys.exc_info

有處理器處理時,返回(type、value和traceback)元組