1. 程式人生 > >廖雪峰python摘錄二輪2

廖雪峰python摘錄二輪2

預編譯 父類 空字符串 返回 提交 update fetch 出了 運行時

1 >>> def set_age(self, age): # 定義一個函數作為實例方法
2 ...     self.age = age
3 ...
4 >>> from types import MethodType
5 >>> s.set_age = MethodType(set_age, s) # 給實例綁定一個方法
6 >>> s.set_age(25) # 調用實例方法
7 >>> s.age # 測試結果
8 25

2、四點需要註意: 1、類和實例都可以動態綁定屬性和方法。類綁定的屬性和方法可以作用於 實例,反之則不可以; 2、類動態綁定方法和實例綁定不同,綁定屬性時兩者相同 類綁定屬性:Student.sex = ‘M‘ 實例綁定屬性:s.sex = ‘M‘ 類綁定方法:from types import MethodType def set_sex(self, sex): self.sex = sex Student.set_sex = set_sex 實例綁定方法:from types import MethodType def set_sex(self, sex): self.sex = sex s.set_sex = MethodType(set_sex, s) 3、slots

可以限制類和實例的屬性。使用slots限制後,類和對應的實例不能隨意動態綁定屬性 4、slots不可繼承。也就是說父類的限制不會繼承給子類。

3、動態語言和靜態語言最大的不同,就是函數和類的定義,不是編譯時定義的,而是運行時動態創建的。

4、

有的錯誤是程序編寫有問題造成的,比如本來應該輸出整數結果輸出了字符串,這種錯誤我們通常稱之為bug,bug是必須修復的。

有的錯誤是用戶輸入造成的,比如讓用戶輸入email地址,結果得到一個空字符串,這種錯誤可以通過檢查用戶輸入來做相應的處理。

還有一類錯誤是完全無法在程序運行過程中預測的,比如寫入文件的時候,磁盤滿了,寫不進去了,或者從網絡抓取數據,網絡突然斷掉了。這類錯誤也稱為異常,在程序中通常是必須處理的,否則,程序會因為各種問題終止並退出。

5、

1 try:
2     foo()
3 except ValueError as e:
4     print(ValueError)
5 except UnicodeError as e:
6     print(UnicodeError)

第二個except永遠也捕獲不到UnicodeError,因為UnicodeErrorValueError的子類,如果有,也被第一個except給捕獲了。

6、使用try...except捕獲錯誤還有一個巨大的好處,就是可以跨越多層調用,比如函數main()調用foo()foo()調用bar(),結果bar()出錯了,這時,只要main()

捕獲到了,就可以處理

 1 def foo(s):
 2     return 10 / int(s)
 3 
 4 def bar(s):
 5     return foo(s) * 2
 6 
 7 def main():
 8     try:
 9         bar(0)
10     except Exception as e:
11         print(Error:, e)
12     finally:
13         print(finally...)

也就是說,不需要在每個可能出錯的地方去捕獲錯誤,只要在合適的層次去捕獲錯誤就可以了。這樣一來,就大大減少了寫try...except...finally的麻煩。

7、

當程序出現錯誤,python會自動引發異常,也可以通過raise顯示地引發異常。一旦執行了raise語句,raise後面的語句將不能執行。

這就是logging的好處,它允許你指定記錄信息的級別,有debuginfowarningerror等幾個級別,當我們指定level=INFO時,logging.debug就不起作用了。同理,指定level=WARNING後,debuginfo就不起作用了。這樣一來,你可以放心地輸出不同級別的信息,也不用刪除,最後統一控制輸出哪個級別的信息。

logging的另一個好處是通過簡單的配置,一條語句可以同時輸出到不同的地方,比如console和文件。

8、讀寫文件前,我們先必須了解一下,在磁盤上讀寫文件的功能都是由操作系統提供的,現代操作系統不允許普通的程序直接操作磁盤,所以,讀寫文件就是請求操作系統打開一個文件對象(通常稱為文件描述符),然後,通過操作系統提供的接口從這個文件對象中讀取數據(讀文件),或者把數據寫入這個文件對象(寫文件)。

很多時候,數據讀寫不一定是文件,也可以在內存中讀寫。

StringIO顧名思義就是在內存中讀寫str。

要把str寫入StringIO,我們需要先創建一個StringIO,然後,像文件一樣寫入即可:

 1 >>> from io import StringIO
 2 >>> f = StringIO()
 3 >>> f.write(hello)
 4 5
 5 >>> f.write( )
 6 1
 7 >>> f.write(world!)
 8 6
 9 >>> print(f.getvalue())
10 hello world!

TypeError: initial_value must be unicode or None, not str 錯誤處理》》》

response.read() returns an instance of bytes while StringIO is an in-memory stream for text only. Use BytesIO instead.

From What‘s new in Python 3.0 - Text Vs. Data Instead Of Unicode Vs. 8-bit

9、

BytesIO

StringIO操作的只能是str,如果要操作二進制數據,就需要使用BytesIO。

BytesIO實現了在內存中讀寫bytes,我們創建一個BytesIO,然後寫入一些bytes:

10、

Python語言特定的序列化模塊是pickle,但如果要把序列化搞得更通用、更符合Web標準,就可以使用json模塊。

json模塊的dumps()loads()函數是定義得非常好的接口的典範。當我們使用時,只需要傳入一個必須的參數。但是,當默認的序列化或反序列機制不滿足我們的要求時,我們又可以傳入更多的參數來定制序列化或反序列化的規則,既做到了接口簡單易用,又做到了充分的擴展性和靈活性。

11、

由於Python是跨平臺的,自然也應該提供一個跨平臺的多進程支持。multiprocessing模塊就是跨平臺版本的多進程模塊。

multiprocessing模塊提供了一個Process類來代表一個進程對象

12、正則表達式中,如果直接給出字符,就是精確匹配。用\d可以匹配一個數字,\w可以匹配一個字母或數字

.可以匹配任意字符

要匹配變長的字符,在正則表達式中,用*表示任意個字符(包括0個),用+表示至少一個字符,用?表示0個或1個字符,用{n}表示n個字符,用{n,m}表示n-m個字符

\d{3}\s+\d{3,8}

我們來從左到右解讀一下:

  1. \d{3}表示匹配3個數字,例如‘010‘

  2. \s可以匹配一個空格(也包括Tab等空白符),所以\s+表示至少有一個空格,例如匹配‘ ‘‘ ‘等;

  3. \d{3,8}表示3-8個數字,例如‘1234567‘

要做更精確地匹配,可以用[]表示範圍,比如:

  • [0-9a-zA-Z\_]可以匹配一個數字、字母或者下劃線;

  • [0-9a-zA-Z\_]+可以匹配至少由一個數字、字母或者下劃線組成的字符串,比如‘a100‘‘0_Z‘‘Py3000‘等等;

  • [a-zA-Z\_][0-9a-zA-Z\_]*可以匹配由字母或下劃線開頭,後接任意個由一個數字、字母或者下劃線組成的字符串,也就是Python合法的變量;

  • [a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精確地限制了變量的長度是1-20個字符(前面1個字符+後面最多19個字符)。

A|B可以匹配A或B,所以(P|p)ython可以匹配‘Python‘或者‘python‘

^表示行的開頭,^\d表示必須以數字開頭。

$表示行的結束,\d$表示必須以數字結束。

你可能註意到了,py也可以匹配‘python‘,但是加上^py$就變成了整行匹配,就只能匹配‘py‘了。

我們強烈建議使用Python的r前綴,就不用考慮轉義的問題了

除了簡單地判斷是否匹配之外,正則表達式還有提取子串的強大功能。用()表示的就是要提取的分組(Group)。比如:

^(\d{3})-(\d{3,8})$分別定義了兩個組,可以直接從匹配的字符串中提取出區號和本地號碼:

除了簡單地判斷是否匹配之外,正則表達式還有提取子串的強大功能。用()表示的就是要提取的分組(Group)。比如:

^(\d{3})-(\d{3,8})$分別定義了兩個組,可以直接從匹配的字符串中提取出區號和本地號碼:

如果一個正則表達式要重復使用幾千次,出於效率的考慮,我們可以預編譯該正則表達式,接下來重復使用時就不需要編譯這個步驟了,直接匹配:

1 >>> import re
2 # 編譯:
3 >>> re_telephone = re.compile(r^(\d{3})-(\d{3,8})$)
4 # 使用:
5 >>> re_telephone.match(010-12345).groups()
6 (010, 12345)
7 >>> re_telephone.match(010-8086).groups()
8 (010, 8086)

13、

因為互聯網協議包含了上百種協議標準,但是最重要的兩個協議是TCP和IP協議,所以,大家把互聯網的協議簡稱TCP/IP協議。

通信的時候,雙方必須知道對方的標識,好比發郵件必須知道對方的郵件地址。互聯網上每個計算機的唯一標識就是IP地址,類似123.123.123.123。如果一臺計算機同時接入到兩個或更多的網絡,比如路由器,它就會有兩個或多個IP地址,所以,IP地址對應的實際上是計算機的網絡接口,通常是網卡。

IP協議負責把數據從一臺計算機通過網絡發送到另一臺計算機。數據被分割成一小塊一小塊,然後通過IP包發送出去。由於互聯網鏈路復雜,兩臺計算機之間經常有多條線路,因此,路由器就負責決定如何把一個IP包轉發出去。IP包的特點是按塊發送,途徑多個路由,但不保證能到達,也不保證順序到達。

14、

一個IP包除了包含要傳輸的數據外,還包含源IP地址和目標IP地址,源端口和目標端口。

端口有什麽作用?在兩臺計算機通信時,只發IP地址是不夠的,因為同一臺計算機上跑著多個網絡程序。一個IP包來了之後,到底是交給瀏覽器還是QQ,就需要端口號來區分。每個網絡程序都向操作系統申請唯一的端口號,這樣,兩個進程在兩臺計算機之間建立網絡連接就需要各自的IP地址和各自的端口號。

一個進程也可能同時與多個計算機建立鏈接,因此它會申請很多端口。

創建Socket時,AF_INET指定使用IPv4協議,如果要用更先進的IPv6,就指定為AF_INET6SOCK_STREAM指定使用面向流的TCP協議,這樣,一個Socket對象就創建成功,但是還沒有建立連接。建立TCP連接後,我們就可以向新浪服務器發送請求,要求返回首頁的內容:

# 發送數據:
s.send(bGET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n)
# 接收數據:
buffer = []
while True:
    # 每次最多接收1k字節:
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b‘‘.join(buffer)

接收數據時,調用recv(max)方法,一次最多接收指定的字節數,因此,在一個while循環中反復接收,直到recv()返回空數據,表示接收完畢,退出循環。

當我們接收完數據後,調用close()方法關閉Socket,這樣,一次完整的網絡通信就結束了:

用TCP協議進行Socket編程在Python中十分簡單,對於客戶端,要主動連接服務器的IP和指定端口,對於服務器,要首先監聽指定端口,然後,對每一個新的連接,創建一個線程或進程來處理。通常,服務器程序會無限運行下去。

同一個端口,被一個Socket綁定了以後,就不能被別的Socket綁定了。

UDP的使用與TCP類似,但是不需要建立連接。此外,服務器綁定UDP端口和TCP端口互不沖突,也就是說,UDP的9999端口與TCP的9999端口可以各自綁定。

15、為了便於程序保存和讀取數據,而且,能直接通過條件快速查詢到指定的數據,就出現了數據庫(Database)這種專門用於集中存儲和查詢的軟件

表是數據庫中存放關系數據的集合,一個數據庫裏面通常都包含多個表,比如學生的表,班級的表,學校的表,等等。表和表之間通過外鍵關聯。

要操作關系數據庫,首先需要連接到數據庫,一個數據庫連接稱為Connection;

連接到數據庫後,需要打開遊標,稱之為Cursor,通過Cursor執行SQL語句,然後,獲得執行結果。

Python定義了一套操作數據庫的API接口,任何數據庫要連接到Python,只需要提供符合Python標準的數據庫驅動即可。

# 導入SQLite驅動:
>>> import sqlite3
# 連接到SQLite數據庫
# 數據庫文件是test.db
# 如果文件不存在,會自動在當前目錄創建:
>>> conn = sqlite3.connect(test.db)
# 創建一個Cursor:
>>> cursor = conn.cursor()
# 執行一條SQL語句,創建user表:
>>> cursor.execute(create table user (id varchar(20) primary key, name varchar(20)))
<sqlite3.Cursor object at 0x10f8aa260>
# 繼續執行一條SQL語句,插入一條記錄:
>>> cursor.execute(insert into user (id, name) values (\‘1\‘, \‘Michael\‘))
<sqlite3.Cursor object at 0x10f8aa260>
# 通過rowcount獲得插入的行數:
>>> cursor.rowcount
1
# 關閉Cursor:
>>> cursor.close()
# 提交事務:
>>> conn.commit()
# 關閉Connection:
>>> conn.close()
 1 >>> conn = sqlite3.connect(test.db)
 2 >>> cursor = conn.cursor()
 3 # 執行查詢語句:
 4 >>> cursor.execute(select * from user where id=?, (1,))
 5 <sqlite3.Cursor object at 0x10f8aa340>
 6 # 獲得查詢結果集:
 7 >>> values = cursor.fetchall()
 8 >>> values
 9 [(1, Michael)]
10 >>> cursor.close()
11 >>> conn.close()

使用Python的DB-API時,只要搞清楚ConnectionCursor對象,打開後一定記得關閉,就可以放心地使用。

使用Cursor對象執行insertupdatedelete語句時,執行結果由rowcount返回影響的行數,就可以拿到執行結果。

使用Cursor對象執行select語句時,通過featchall()可以拿到結果集。結果集是一個list,每個元素都是一個tuple,對應一行記錄。

在Python中操作數據庫時,要先導入數據庫對應的驅動,然後,通過Connection對象和Cursor對象操作數據。

要確保打開的Connection對象和Cursor對象都正確地被關閉,否則,資源就會泄露。

如何才能確保出錯的情況下也關閉掉Connection對象和Cursor對象呢?請回憶try:...except:...finally:...的用法。

廖雪峰python摘錄二輪2