封面
前言
-
“Python”中文翻譯“蟒蛇”
-
Python的優點:
- 簡單、易學、免費、開源:Python簡單、易學。我們可以自由發布其復制版本,閱讀、修改其源代碼,將其(部分)用於新軟件中。
- 解釋型:Python是邊解釋邊執行的,Python解釋器會將源代碼轉換為中間字節碼形式,然后將其解釋為機器語言並執行。
- 可移植:Python解釋器已被移植在許多平台上,Python程序無須經過修改就可以在多個平台上運行。
- 代碼規范:Python所采用的強制縮進的方式,使得其代碼具有極佳的可讀性。
- 面向對象:與C++和Java等相比,Python以強大而簡單的方式實現了面向對象編程。
- 膠水語言:標准版本的Python調用C語言,並可以借助C語言的接口驅動調用所有編程語言。
- 豐富的庫:Python的標准庫種類繁多,可以幫助處理各種工作,我們不需要安裝就可以直接使用這些庫。
- 動態類型:Python不會檢查數據類型,在聲明變量時不需要指定數據類型。
編寫和運行Python程序方式:
- 交互方式
- 文件方式
1.交互方式
Python安裝包提供了交互式運行工具——Python Shell,在安裝好Python后,我們就可以單擊Windows“開始”菜單打開Python 3.x了。
2.文件方式
通過文件方式編寫和運行Python程序時,首先需要編寫Python代碼,然后在Windows下啟動命令提示符,再使用Python指令運行Python代碼文件。
編寫Python代碼時,既可以使用任意一種文本編輯工具,也可以使用專業的IDE(Integrated Development Environments,集成開發環境)工具。
一些基礎概念
標識符
標識符就是變量、函數、屬性、類、模塊等可以由程序員指定名稱的代碼元素。構成標識符的字符均遵循一定的命名規則。
注:Unicode是國際組織制定的可以容納世界上所有文字和符號的字符編碼方案。
- Python中標識符的命名規則:
- 區分大小寫:Myname與myname是兩個不同的標識符。
- 首字符可以是下畫線(_)或字母,但不能是數字。
- 除首字符外的其他字符必須是下畫線、字母和數字。
- 關鍵字不能作為標識符。
- 不要使用Python的內置函數作為自己的標識符。
關鍵字
關鍵字是由語言本身定義好的有特殊含義的代碼元素
變量
在Python中為一個變量賦值的同時就聲明了該變量,該變量的數據類型就是賦值數據所屬的類型,該變量還可以接收其他類型的數據。
·注:Python中,聲明變量后,也可以接受其他類型的數據。這是與Java和C等編程語言的區別。
語句
Python代碼是由關鍵字、標識符、表達式和語句等構成的,語句是代碼的重要組成部分。在Python中,一行代碼表示一條語句,在一般情況下語句結束時不加分號。
代碼注釋
在使用#(井號)時,#位於注釋行的開頭,#后面有一個空格,接着是注釋的內容。
模塊
在Python中一個模塊就是一個文件,模塊是保存代碼的最小單位,在模塊中可以聲明變量、函數、屬性和類等Python代碼元素。
- 一個模塊訪問另一個模塊中的代碼元素——三種導入語句:
- ①import<模塊名>:通過這種方式會導入m2模塊的所有代碼元素,在訪問時需要加前綴“m2.”
- ②from<模塊名>import<代碼元素>:通過這種方式會導入m2中的x變量,在訪問時不需要加前綴“m2.”
- ③from<模塊名>import<代碼元素>as<代碼元素別名>:與②類似,在當前m1模塊的代碼元素(x變量)與要導入的m2模塊的代碼元素(x變量)名稱有沖突時,可以給要導入的代碼元素(m2中的x)一個別名x2
數字類型的數據
在Python中有6種主要的內置數據類型:數字、字符串、列表、元組、集合和字典。列表、元組、集合和字典可以容納多項數據,在本書中把它們統稱為容器類型的數據。
Python中的數字類型有4種:整數類型、浮點類型、復數類型和布爾類型。需要注意的是,布爾類型也是數字類型,它事實上是整數類型的一種。
Python中的整數類型為int類
示例:
Python的浮點類型為float類,浮點類型主要用來存儲小數數值
示例:
Python的復數類型
示例:
Python的布爾類型為bool類
bool是int的子類,他只有兩個值:True和Flase
示例:
數字類型的相互轉換
在Python的數字類型中,除復數隱式類型的轉換數字之間可以進行數學計算,在進行數學計算時若數字類型不同,則會發生隱式類型的轉換。
隱式類型的轉換
數字之間可以進行數學計算,在進行數學計算時若數字類型不同,則會發生隱式類型的轉換
示例:
顯式類型的轉換
示例:
運算符
我們可以通過運算符把數據連接起來,形成表達式,進而通過表達式進行運算,最后返回一個結果。
算數運算符
算術運算符用於組織整數類型和浮點類型的數據,有一元運算符和二元運算符之分。
一元算術運算符有兩個:+(正號)和-(負號),例如:+a還是a,-a是對a的取反運算。
二元算術運算符如表所示。
·注:True被當作整數1進行運算,False被當作整數0進行運算。在操作數中如有浮點數字,則表達式的計算結果也是浮點類型。
比較運算符
比較運算符用於比較兩個表達式的大小,其結果是布爾類型的數據,即True或False。
·注:比較運算符可用於任意類型的數據,但參與比較的兩種類型的數據要相互兼容,即能進行隱式轉換。例如:整數、浮點數和布爾這三種類型是相互兼容的。
邏輯運算符
邏輯運算符用於對布爾型變量進行運算,其結果也是布爾型。
·注:Python也采用了“短路”設計。
即
位運算符
位運算是以二進位(bit)為單位進行運算的,操作數和結果都是整數類型的數據。
或運算:
與運算:
異或運算:
取反運算(原碼、補碼、反碼):
賦值運算符
補充:進制的前綴與后綴 |
運算符的優先級
程序流程控制
控制程序的流程,使得程序具有“判斷能力”,能夠像人腦一樣分析問題。
分支語句(條件語句)
if語句三種結構:
if結構
if-else結構
if-elif-else結構
if結構
語法:
·注:1個Tab=4個半角空格
示例:
if-else結構
語法:
示例:
if-elif-else結構
語法:
示例:
循環語句
Python支持兩種循環語句:while和for。
while語句
語法:
示例:
while-else語句
示例:
for語句
語法:
示例:
for-else語句
示例:
跳轉語句
跳轉語句能夠改變程序的執行順序,包括break、continue和return。break和continue用於循環體中,而return用於函數中。
break語句
break語句用於強行退出循環體,不再執行循環體中剩余的語句。
示例:
continue語句
continue語句用於結束本次循環,跳過循環體中尚未執行的語句,接着進行終止條件的判斷,以決定是否繼續循環。
示例:
循環語句實踐:計算水仙花數
水仙花數是一個三位數,三位數各位的立方之和等於三位數本身。
關於else的注意事項
在循環體正常結束時會執行else語句,如果發生中斷,則不運行else語句 |
容器類型的數據
Python內置的數據類型如序列(列表、元組等)、集合和字典等可以容納多項數據,我們稱它們為容器類型的數據。
序列
序列(sequence)是一種可迭代的、元素有序的容器類型的數據。
序列包括列表(list)、字符串(str)、元組(tuple)和字節序列(bytes)等。
序列的索引操作
序列中的元素都是有序的,每一個元素都帶有序號,這個序號叫作索引。索引有正值索引和負值索引之分。
我們是通過下標運算符訪問序列中的元素的,下標運算符是跟在容器數據后的一對中括號([]),中括號帶有參數,對於序列類型的數據,這個參數就是元素的索引序號。
示例:
加和乘操作
加(+)和乘()運算符也可以用於序列中的元素操作。加(+)運算符可以將兩個序列連接起來,乘()運算符可以將兩個序列重復多次。
示例:
切片操作
序列的切片(Slicing)就是從序列中切分出小的子序列。
切片運算符的語法形式為[start:end:step]。其中,start是開始索引,end是結束索引,step是步長(切片時獲取的元素的間隔,可以為正整數,也可以為負整數)。
注意:切下的小切片包括start位置的元素,但不包括end位置的元素,start和end都可以省略。
示例:
成員測試
成員測試運算符有兩個:in和not in,in用於測試是否包含某一個元素,not in用於測試是否不包含某一個元素。
示例:
列表
列表(list)是一種可變序列類型,我們可以追加、插入、刪除和替換列表中的元素。
創建列表
創建列表有兩種方法。
1 list(iterable)函數:參數iterable是可迭代對象(字符串、列表、元組、集合和字典等)。
2 [元素1,元素2,元素3,⋯]:指定具體的列表元素,元素之間以逗號分隔,列表元素需要使用中括號括起來。
示例:
追加元素
列表是可變的序列對象,列表可以追加元素。
1 在列表中追加單個元素時,可以使用列表的append(x)方法。
2 在列表中追加多個元素時,可以使用加(+)運算符或列表的extend(t)方法。
·區分:
示例:
插入元素
想向列表中插入元素時,可以使用列表的list.insert(i,x)方法,其中,i指定索引位置,x是要插入的元素。
示例:
替換元素
想替換列表中的元素時,將列表下標索引元素放在賦值符號(=)的左邊,進行賦值即可。
示例:
刪除元素
想在列表中刪除元素時,可使用列表的list.remove(x)方法,如果找到匹配的元素x,則刪除該元素,如果找到多個匹配的元素,則只刪除第一個匹配的元素。
示例:
元組
元組(tuple)是一種不可變序列類型。
創建元組
創建元組時有兩種方法。
1 tuple(iterable)函數:參數iterable是可迭代對象(字符串、列表、元組、集合和字典等)。
2 (元素1,元素2,元素3,⋯):指定具體的元組元素,元素之間以逗號分隔。對於元組元素,可以使用小括號括起來,也可以省略小括號。
示例:
元組拆包
創建元組,並將多個數據放到元組中,這個過程被稱為元組打包。
與元組打包相反的操作是拆包,就是將元組中的元素取出,分別賦值給不同的變量。
示例:
集合
集合(set)是一種可迭代的、無序的、不能包含重復元素的容器類型的數據。
創建集合
我們可以通過以下兩種方式創建集合。
1 set(iterable)函數:參數iterable是可迭代對象(字符串、列表、元組、集合和字典等)。
2 {元素1,元素2,元素3,⋯}:指定具體的集合元素,元素之間以逗號分隔。對於集合元素,需要使用大括號括起來。
示例:
修改集合
修改集合類似於修改列表,可以向其中插入和刪除元素。修改可變集合有如右所示的常用方法。
add(elem):添加元素,如果元素已經存在,則不能添加,不會拋出錯誤。
remove(elem):刪除元素,如果元素不存在,則拋出錯誤。
clear( ):清除集合
示例:
字典
字典(dict)是可迭代的、通過鍵(key)來訪問元素的可變的容器類型的數據。
字典由兩部分視圖構成:鍵視圖和值視圖。鍵視圖不能包含重復的元素,值視圖能。在鍵視圖中,鍵和值是成對出現的。
創建字典
我們可以通過以下兩種方法創建字典。
1 dict( )函數。
2 {key1:value1,key2:value2,...,key_n:value_n}:指定具體的字典鍵值對,鍵值對之間以逗號分隔,最后用大括號括起來。
示例:
修改字典
字典可以被修改,但都是針對鍵和值同時操作的,對字典的修改包括添加、替換和刪除。
示例:
訪問字典視圖
我們可以通過字典中的三種方法訪問字典視圖。
items( ):返回字典的所有鍵值對視圖。
keys( ):返回字典鍵視圖。
values( ):返回字典值視圖。
解釋:
第2行:返回字典的所有鍵值對視圖dict_items
第4行:dict_items可以使用list( )函數返回鍵值對列表
第6行:返回字典鍵視圖dict_keys
第8行:dict_keys可以使用list( )函數返回鍵列表
第10行:返回字典值視圖dict_values
第12行:dict_values可以使用list( )函數返回值列表
遍歷字典
什么是遍歷
示例:
字符串
字符串的表示方式
字符串有三種表示方式:普通字符串、原始字符串和長字符串。
普通字符串
普通字符串指用單引號(')或雙引號(")括起來的字符串。
字符轉義
常用轉義符:
示例:
原始字符串
示例:
長字符串
如果要使用字符串表示一篇文章,其中包含了換行、縮進等排版字符,則可以使用長字符串表示。對於長字符串,要使用三個單引號(''')或三個雙引號(""")括起來。
示例:
字符串與數字的相互轉換
字符串和數字是不兼容的兩種數據類型,不能進行隱式轉換,只能通過函數進行顯式轉換。
將字符串轉換為數字
將字符串轉換為數字,可以使用int( )和float( )實現,如果成功則返回數字,否則引發異常。
示例:
在默認情況下,int( )函數都將字符串參數當作十進制數字進行轉換,所以int('AB')會失敗。int( )函數也可以指定基數(進制)。
將數字轉換為字符串【str()】
將數字轉換為字符串,可以使用str( )函數,str( )函數可以將很多類型的數據都轉換為字符串。
示例:
格式化字符串【format()】
使用占位符
要想將表達式的計算結果插入字符串中,則需要用到占位符。對於占位符,使用一對大括號({})表示。
默認占位符
參數序號占位符
參數名占位符
示例:
格式化控制符
在占位符中還可以有格式化控制符,對字符串的格式進行更加精准的控制
格式化控制符位於占位符索引或占位符名字的后面,之間用冒號分隔,語法:{參數序號:格式控制符}或{參數名:格式控制符}。
字符串的格式化控制符及其說明如下表所示:
示例:
操作字符串
字符串查找
字符串的find( )方法用於查找子字符串。該方法的語法為str.find(sub[,start[,end]]),表示:在索引start到end之間查找子字符串sub,如果找到,則返回最左端位置的索引;如果沒有找到,則返回-1。
注:在Python文檔中[]表示可以省略部分內容,find()方法的參數[,start[,end]]表示start和end都可以省略
示例:
字符串替換
若想進行字符串替換,則可以使用replace( )方法替換匹配的子字符串,返回值是替換之后的字符串。該方法的語法為str.replace(old,new[,count]),表示:用new子字符串替換old子字符串。count參數指定了替換old子字符串的個數,如果count被省略,則替換所有old子字符串。
示例:
字符串分割
若想進行字符串分割,則可以使用split( )方法,按照子字符串來分割字符串,返回字符串列表對象。該方法的語法為str.split(sep=None,maxsplit=-1),表示:使用sep子字符串分割字符串str。maxsplit是最大分割次數,如果maxsplit被省略,則表示不限制分割次數。
示例:
實踐:統計英文文章中單詞出現的頻率
函數
定義函數
自定義函數的語法格式如下:
形式參數
由於定義函數時的參數不是實際數據,會在調用函數時傳遞給他們是實際數據,所以我們定義函數時的參數成為形式參數,簡稱形參;稱調用函數時傳遞的實際數據為實際參數,簡稱實參。可以將形參理解為在函數中定義的變量。
示例:
調用函數
使用位置參數調用函數
在調用函數時傳遞的實參與定義函數時的形參順序一致,這是調用函數的基本形式。
示例:
使用關鍵字參數調用函數
在調用函數時可以采用“關鍵字=實參”的形式,其中,關鍵字的名稱就是定義函數時形參的名稱。
示例:
參數的默認值
示例:
可變參數
基於元組的可變參數(*可變參數)
*可變參數在函數中被組裝成一個元組。
示例:
基於字典的可變參數(**可變參數)
**可變參數在函數中被組裝成一個字典。
示例:
函數中變量的作用域
變量可以在模塊中創建,作用域(變量的有效范圍)是整個模塊,被稱為全局變量。變量也可以在函數中創建,在默認情況下作用域是整個函數,被稱為局部變量。
示例:
函數類型
Python中的任意一個函數都有數據類型,這種數據類型是function,被稱為函數類型。
理解函數類型
函數類型的數據與其他類型的數據是一樣的,任意類型的數據都可以作為函數返回值使用,還可以作為函數參數使用。因此,一個函數可以作為另一個函數返回值使用,也可以作為另一個函數參數使用。
示例:
add( )和sub( )函數有兩個數字參數,具有相同的函數類型。square( )函數只有一個數字參數,所以square( )與add( )、sub( )函數的類型不同。
數據處理的函數
在Python中定義了一些用於數據處理的函數,如filter( )和map( )等。我們先介紹filter( )函數。
過濾函數filter( )
filter( )函數用於對容器中的元素進行過濾處理。
filter( )函數的語法如下:
參數function是一個提供過濾條件的函數,返回布爾值。
參數iterable是容器類型的數據。
示例:
映射函數map( )
map( )函數用於對容器中的元素進行映射(或變換)。例如:我想將列表中的所有元素都乘以2,返回新的列表。
map( )函數的語法如下:
參數function是一個提供變換規則的函數,返回變換之后的元素。
參數iterable是容器類型的數據。
示例:
lambda( )函數
我們之前學習的函數都是有名稱的函數,例如在8.1節定義的rect_area( )函數,rect_area就是其函數名。我們也可以定義匿名函數,匿名函數就是沒有名稱的函數。
在Python中使用lambda關鍵字定義匿名函數。lambda關鍵字定義的函數也被稱為lambda( )函數,定義lambda( )函數的語法如下。
“參數列表”與函數的參數列表是一樣的,但不需要用小括號括起來
lambda( )函數與有名稱的函數一樣,都是函數類型。add( )和sub( )函數可以被lambda( )函數替代。
示例:
類與對象
類和對象都是面向對象中的重要概念。面向對象是一種編程思想,即按照真實世界的思維方式構建軟件系統。
定義類
Python中的數據類型都是類,我們可以自定義類,即創建一種新的數據類型。Python中類的定義語法格式如圖所示。
示例:
小汽車(Car)類繼承了object類,object類是所有類的根類,在Python中任何一個類(除object外)都直接或間接地繼承了object,直接繼承object時(object)部分的代碼可以省略。
pass語句的作用:pass語句只用於維持程序結構的完整。我們在編程時若不想馬上編寫某些代碼,又不想有語法錯誤,就可以使用pass語句占位。
創建對象
類相當於一個模板,依據這樣的模板來創建對象,就是類的實例化,所以對象也被稱為“實例”。
示例:
類的成員
分類:
成員變量也被稱為數據成員,保存了類或對象的數據。例如,學生的姓名和學號。
構造方法是一種特殊的函數,用於初始化類的成員變量。
成員方法是在類中定義的函數。
屬性是對類進行封裝而提供的特殊方法。
實例變量
實例變量就是對象個體特有的“數據”,例如狗狗的名稱和年齡等。
示例:
構造方法
類中的__init__( )方法是一個非常特殊的方法,用來創建和初始化實例變量,這種方法就是“構造方法”。在定義__init__( )方法時,它的第1個參數應該是self,之后的參數用來初始化實例變量。調用構造方法時不需要傳入self參數。
示例:
實例方法
實例方法與實例變量一樣,都是某個實例(或對象)個體特有的方法。
定義實例方法時,它的第1個參數也應該是self,這會將當前實例與該方法綁定起來,這也說明該方法屬於實例。在調用方法時不需要傳入self,類似於構造方法。
示例:
類變量
類變量是屬於類的變量,不屬於單個對象。
例如,有一個Account(銀行賬戶)類,它有三個成員變量:amount(賬戶金額)、interest_rate (利率)和owner(賬戶名)。amount和owner對於每一個賬戶都是不同的,而interest_rate對於所有賬戶都是相同的。amount和owners是實例變量,interest_rate是所有賬戶實例共享的變量,它屬於類,被稱為“類變量”。、
類方法
類方法與類變量類似,屬於類,不屬於個體實例。在定義類方法時,它的第1個參數不是self,而是類本身。
示例:
注:
封裝性
封裝性是面向對象重要的基本特性之一。封裝隱藏了對象的內部細節,只保留有限的對外接口,外部調用者不用關心對象的內部細節,使得操作對象變得簡單。
例如,一台計算機內部極其復雜,有主板、CPU、硬盤和內存等,而一般人不需要了解它的內部細節。計算機制造商用機箱把計算機封裝起來,對外提供了一些接口,如鼠標、鍵盤和顯示器等,使用計算機就變得非常簡單。
私有變量
為了防止外部調用者隨意存取類的內部數據(成員變量),內部數據(成員變量)會被封裝為“私有變量”。外部調用者只能通過方法調用私有變量。
在默認情況下,Python中的變量是公有的,可以在類的外部訪問它們。如果想讓它們成為私有變量,則在變量前加上雙下畫線(__)即可。
示例:
由於在類的外部不可以訪問私有變量,因此上述代碼在運行時會發生錯誤。
私有方法
私有方法與私有變量的封裝是類似的,在方法前加上雙下畫線(__)就是私有方法了。
示例:
由於在類的外部不可以訪問私有方法,因此上述代碼在運行時會發生錯誤.
使用屬性
為了實現對象的封裝,在一個類中不應該有公有的成員變量,這些成員變量應該被設計為私有的,然后通過公有的set (賦值)和get(取值)方法訪問。
示例:
屬性在本質上就是兩個方法,在方法前加上裝飾器使得方法成為屬性。屬性使用起來類似於公有變量,可以在賦值符(=)左邊或右邊,左邊被賦值,右邊取值。
繼承性
繼承性也是面向對象重要的基本特性之一。
9.6.1 Python中的繼承
在Python中聲明子類繼承父類,語法很簡單,定義類時在類的后面使用一對小括號指定它的父類就可以了。
示例:
多繼承
在Python中,當子類繼承多個父類時,如果在多個父類中有相同的成員方法或成員變量,則子類優先繼承左邊父類中的成員方法或成員變量,從左到右繼承級別從高到低。
示例:
方法重寫
如果子類的方法名與父類的方法名相同,則在這種情況下,子類的方法會重寫(Override)父類的同名方法。
示例:
多態性
多態性也是面向對象重要的基本特性之一。“多態”指對象可以表現出多種形態。
繼承與多態
在多個子類繼承父類,並重寫父類方法后,這些子類所創建的對象之間就是多態的。這些對象采用不同的方式實現父類方法。
示例:
鴨子類型測試與多態
Python的多態性更加靈活,支持鴨子類型測試。鴨子類型測試指:若看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥可以被稱為鴨子。
由於支持鴨子類型測試,所以Python解釋器不檢查發生多態的對象是否繼承了同一個父類,只要它們有相同的行為(方法),它們之間就是多態的。
例如,我們設計一個函數start( ),它接收具有“叫”speak( )方法的對象,代碼如下:
我們定義了幾個類,它們都有speak( )方法。
start( )函數可以接收所有speak( )方法對象。
異常處理
為增強程序的健壯性,我們也需要考慮異常處理方面的內容。例如,在讀取文件時需要考慮文件不存在、文件格式不正確等異常情況。
第一個異常——除零異常
在數學中,任何整數都不能除以0,如果在計算機程序中將整數除以0,則會引發異常。
示例:
捕獲異常
我們不能防止用戶輸入0,但在出現異常后我們能捕獲並處理異常,不至於讓程序發生終止並退出。亡羊補牢,為時未晚。
try-except語句
在try代碼塊中包含在執行過程中可能引發異常的語句,如果沒有發生異常,則跳到except代碼塊執行,這就是異常捕獲。
異常捕獲是通過try-except語句實現的,基本的try-except語句的語法如下。
try-except語句的執行流程如下。
示例:
從運行的結果可以看出,在輸入數字0后,異常發生,跳到except代碼塊執行。
修改示例:
多個except代碼塊
多條語句可能會引發多種不同的異常,對每一種異常都會采用不同的處理方式。針對這種情況,我們可以在一個try后面跟多個except代碼塊,語法如下:
示例:
多重異常捕獲
示例:
try-except語句嵌套
示例:
使用finally代碼塊釋放資源
有時在try-except語句中會占用一些資源,例如打開的文件、網絡連接、打開的數據庫及數據結果集等都會占用計算機資源,需要程序員釋放這些資源。為了確保這些資源能夠被釋放,可以使用finally代碼塊。
在try-except語句后面還可以跟一個finally代碼塊,語法如下。
無論是try代碼塊正常結束還是except代碼塊異常結束,都會執行finally代碼塊。
示例:
自定義異常類
示例:
手動引發異常
示例:
常用的內置模塊
數學計算模塊——math
在math模塊中包含數學運算相關的函數等,例如指數、對數、平方根和三角函數等。
本節介紹math模塊中的一些常用函數。
示例:
日期時間模塊——datetime
Python官方提供的日期和時間模塊主要是datetime模塊。在datetime模塊中提供了如下幾個類。
datetime:包含時間和日期。
date:只包含日期。
time:只包含時間。
timedelta:計算時間跨度。
tzinfo:時區信息。
datetime類
datetime類表示日期和時間等信息,我們可以使用如下構造方法創建datetime對象:
示例:
datetime類的常用方法如下。
datetime.today( ):返回當前的本地日期和時間。
datetime.now(tz=None):返回指定時區的當前日期和時間,參數tz用於設置時區,如果參數tz為None或省略,則等同於today( )。
datetime.fromtimestamp(timestamp,tz=None):返回與UNIX時間戳對應的本地日期和時間。UNIX時間戳是從1970年1月1日00:00:00開始到現在為止的總秒數。我們在Python Shell中運行代碼,看看運行結果怎樣。
示例:
date類
date類表示日期信息,我們可以使用如下構造方法創建date對象:
這些參數的含義和取值范圍與datetime類一樣
date類的常用方法如下。
date.today( ):返回當前的本地日期。
date.fromtimestamp(timestamp):返回與UNIX時間戳對應的本地日期。
示例:
time類
time類表示一天中的時間信息,我們可以使用如下構造方法創建time對象:
這些參數的含義和取值范圍與datetime類一樣。
示例:
計算時間跨度類——timedelta
timedelta類的構造方法:
其中的所有參數都可以為整數或浮點數,也可以為正數或負數,如右表所示。
示例:
timedelta可以表示正數或負數時間的間隔,如下代碼是等效的。
將日期時間與字符串相互轉換
我們經常會遇到將日期時間與字符串相互轉換的情況。
1 將日期時間對象轉換為字符串時,稱之為日期時間格式化。在Python中使用strftime( )方法進行日期時間的格式化,在datetime、date和time三個類中都有一個實例方法strftime(format)。
2 將字符串轉換為日期時間對象的過程,叫作日期時間解析。在Python中使用datetime.strptime(date_string,format)類方法進行日期時間解析。
在strftime( )和strptime( )方法中都有一個格式化參數format,用來控制日期時間的格式,常用的日期和時間格式控制符如下表所示。
示例:
正則表達式模塊——re
正則表達式指預先定義好一個“字符串模板”,通過這個“字符串模板”可以匹配、查找和替換那些匹配“字符串模板”的字符串。
字符串匹配
字符串匹配指驗證一個字符串是否符合指定的“字符串模板”,常用於用戶輸入驗證。例如,用戶在注冊時要輸入郵箱,所以需要驗證郵箱是否有效,這就要用到字符串匹配驗證。
我們使用match(p,text)函數進行字符串匹配,其中的參數p是正則表達式,即字符串模板,text是要驗證的字符串。如果匹配成功,則返回一個Match對象(匹配對象),否則返回None。
示例:
字符串查找
字符串查找指從一個字符串中查找匹配正則表達式的子字符串,常用於數據分析、網絡爬蟲等數據處理中。
常用的字符串查找函數如下。
search(p,text):在text字符串中查找匹配的內容,如果找到,則返回第1個匹配的Match對象,否則返回None。p是正則表達式。
findall(p,text):在text字符串中查找所有匹配的內容,如果找到,則返回所有匹配的字符串列表;如果一個都沒有匹配,則返回None。p是正則表達式。
示例:
字符串替換
正則表達式的字符串替換函數是sub( ),該函數替換匹配的子字符串,返回值是替換之后的字符串,其語法格式如下:
其中,參數pattern是正則表達式;參數repl是用於替換的新字符串;參數string是即將被替換的舊字符串;參數count是要替換的最大數量,默認值為零,表示不限制替換數量。
字符串分割
在Python中使用re模塊中的split( )函數進行字符串分割,該函數按照匹配的子字符串進行字符串分割,返回字符串列表對象,其語法格式如下:
其中,參數pattern是正則表達式;參數string是要分割的字符串;參數maxsplit是最大分割次數;maxsplit的默認值為零,表示分割次數沒有限制。
文件讀寫
文件是數據的載體,程序可以從文件中讀取數據,也可以將數據寫入文件中。
打開文件
我們在使用文件之前要先將文件打開,這通過open( )函數實現。open( )函數的語法如下:
open( )函數中的參數還有很多,這里介紹4個常用參數,這些參數的含義如下。
1. file參數
file參數用於表示要打開的文件,可以是字符串或整數。如果file是字符串,則表示文件名,文件名既可以是當前目錄的相對路徑,也可以是絕對路徑;如果file是整數,則表示一個已經打開的文件。
2. mode參數
mode參數用於設置文件打開模式,用字符串表示,例如rb表示以只讀模式打開二進制文件。用於設置文件打開模式的字符串中的每一個字符都表示不同的含義,對這些字符的具體說明如下。
t:以文本文件模式打開文件。
b:以二進制文件模式打開文件。
r:以只讀模式打開文件。
w:以只寫模式打開文件,不能讀內容。如果文件不存在,則創建文件;如果文件存在,則覆蓋文件的內容。
x:以獨占創建模式打開文件,如果文件不存在,則創建並以寫入模式打開;如果文件已存在,則引發FileExistsError異常。
a:以追加模式打開文件,不能讀內容。如果文件不存在,則創建文件;如果文件存在,則在文件末尾追加。
+:以更新(讀寫)模式打開文件,必須與r、w或a組合使用,才能設置文件為讀寫模式。
這些字符可以進行組合,以表示不同類型的文件的打開模式,如下表所示。
3. encoding參數
encoding用來指定打開文件時的文件編碼,默認是UTF-8編碼,主要用於打開文本文件。
4. errors參數
errors參數用來指定在文本文件發生編碼錯誤時如何處理。推薦errors參數的取值為'ignore',表示在遇到編碼錯誤時忽略該錯誤,程序會繼續執行,不會退出。
示例:
注:
關閉文件
在打開文件后,如果不再使用該文件,則應該將其關閉,會用到close( )方法。
在finally代碼塊中關閉文件
對文件的操作往往會拋出異常,為了保證對文件的操作無論是正常結束還異常結束,都能夠關閉文件,我們應該將對close( )方法的調用放在異常處理的finally代碼塊中。
示例:
在with as代碼塊中關閉文件
with as提供了一個代碼塊,在as后面聲明一個資源變量,在with as代碼塊結束之后自動釋放資源。
示例:
讀寫文本文件
讀寫文本文件的相關方法如下。
read(size=-1):從文件中讀取字符串,size限制讀取的字符數,size=-1指對讀取的字符數沒有限制。
readline(size=-1):在讀取到換行符或文件尾時返回單行字符串。如果已經到文件尾,則返回一個空字符串。size是限制讀取的字符數,size=-1表示沒有限制。
readlines( ):讀取文件數據到一個字符串列表中,每一行數據都是列表的一個元素。
write(s):將字符串s寫入文件中,並返回寫入的字符數。
writelines(lines):向文件中寫入一個字符串列表。不添加行分隔符,因此通常為每一行末尾都提供行分隔符。
flush( ):刷新寫緩沖區,在文件沒有關閉的情況下將數據寫入文件中。
復制文本文件
讀寫二進制文件
二進制文件的讀寫單位是字節,不需要考慮編碼問題。二進制文件的主要讀寫方法如下。
read(size=-1):從文件中讀取字節,size限制讀取的字節數,如果size=-1,則讀取全部字節。
readline(size=-1):從文件中讀取並返回一行。size是限制讀取的行數,如果size=-1,則沒有限制。
readlines( ):讀取文件數據到一個字節列表中,每一行數據都是列表的一個元素。、
write(b):寫入b字節,並返回寫入的字節數。
writelines(lines):向文件中寫入一個字節列表。不添加行分隔符,因此通常為每一行末尾都提供行分隔符。
flush( ):刷新寫緩沖區,在文件沒有關閉的情況下將數據寫入文件中。
復制二進制文件
注:
圖形用戶界面
Python中的圖形用戶界面開發庫
注:Qt是一個跨平台的C++應用程序開發框架,被廣泛用於開發GUI程序,也可用於開發非GUI程序。
1 TkinterTkinter是Python官方提供的圖形用戶界面開發庫,用於封裝Tk GUI工具包,跨平台。但是,Tkinter工具包所包含的控件較少,幫助文檔不健全,不便於我們開發復雜的圖形用戶界面。
2 PyQtPyQt是非Python官方提供的圖形用戶界面開發庫,用於封裝Qt工具包,跨平台。若想使用PyQt工具包,則需要額外安裝軟件包。
3 wxPythonwxPython是非Python官方提供的圖形用戶界面開發庫,也跨平台。它提供了豐富的控件,可用於開發復雜的圖形用戶界面。它的工具包幫助文檔很完善,案例也很豐富。
安裝wxPython
在命令提示符(終端)窗口輸入pip指令:
在Windows平台上通過pip指令安裝wxPython,在命令提示符窗口輸入如下指令。
如果安裝成功,則可以出現如下窗口。
第一個wxPython程序
圖形用戶界面主要是由窗口及窗口中的控件構成的,編寫wxPython程序其實主要是創建窗口和添加控件的過程。
若要構建一個最簡單的wxPython程序,則至少需要一個應用(wx.App)對象和一個窗口(wx.Frame)對象。
通過Python指令在命令提示符窗口中運行文件。
運行並輸出結果,彈出如下窗口。
自定義窗口類
在窗口中添加控件
我們在窗口中添加兩個控件:一個面板(Panel)和一個靜態文本(StaticText)。面板是一個沒有標題欄的容器(可以容納其他控件的控件)。
事件處理
圖形界面的控件要響應用戶的操作,就必須添加事件處理機制。事件處理的過程如下圖所示。
其中涉及的主要內容如下。
1 事件源:事件發生的場所,就是各個控件,例如按鈕事件的事件源是按鈕。
2 事件:wxPython中的事件被封裝為事件類wx.Event及其子類,例如按鈕事件類是wx.CommandEvent,鼠標事件類是wx.MoveEvent。
3 事件處理程序:一個響應用戶事件的方法。下面通過一個示例介紹事件處理流程。在以下窗口中有一個按鈕和一個靜態文本,在單擊OK按鈕時會改變靜態文本顯示的內容。
下面通過一個示例介紹事件處理流程。在以下窗口中有一個按鈕和一個靜態文本,在單擊OK按鈕時會改變靜態文本顯示的內容。
布局管理
wxPython提供了布局管理器類幫助實現界面布局,主要分為兩大類:盒子布局管理器和網格布局管理器。盒子布局類似於CSS中的彈性布局,非常靈活,我們重點介紹盒子布局。
盒子布局管理器
盒子布局管理器類是wx.BoxSizer,Box布局管理器是最常用的布局管理器,它可以讓其中的子窗口(或控件)沿垂直或水平方向布局。
1 創建盒子布局管理器對象
我們使用wx.BoxSizer類創建盒子布局管理器對象,主要的構造方法如下:
設置為水平方向布局,
設置為垂直方向布局。
wx.HORIZONTAL是默認值,可以省略
2 添加子窗口(或控件)到父窗口
我們使用wx.BoxSizer對象的Add( )方法添加子窗口(或控件)到父窗口,對Add( )方法的語法說明如下:
添加到父窗口
proportion參數用於設置當前子窗口(或控件)在父窗口中所占的空間比例;flag參數是布局標志,用來控制對齊方式、邊框和調整尺寸;border參數用於設置邊框的寬度。
下面重點介紹flag標志,flag標志可以分為對齊、邊框和調整尺寸。
flag對齊標志如下表所示。
flag邊框標志如下表所示。
flag調整尺寸標志如下表所示。
重構事件處理示例
盒子布局管理器嵌套示例
在本例中采用了嵌套布局,首先將兩個按鈕(b1和b2)放到一個水平方向的盒子布局管理器對象(hbox)中,然后將一個靜態文本(statictext)和hbox放到一個垂直方向的盒子布局管理器對象(vbox)中。
控件
wxPython的所有控件都繼承自wx.Control類。之前的示例已經使用了靜態文本和按鈕,本節重點介紹文本輸入控件、單選按鈕、復選框、列表和靜態圖片控件。
文本輸入控件
文本輸入控件(wx.TextCtrl)是可以輸入文本的控件。
復選框和單選按鈕
多選控件是復選框(wx.CheckBox),復選框(wx.CheckBox)有時也能單獨使用,能提供兩種狀態的開和關。
單選控件是單選按鈕(wx.RadioButton),同一組的多個單選按鈕應該具有互斥性,就是當一個按鈕按下時,其他按鈕一定釋放。
在界面中實現一組復選框和一組單選按鈕。
列表
對列表控件可以進行單選或多選,列表控件類是wx.ListBox。
在界面中實現以下兩個列表控件。
wx.LB_SINGLE:單選。
wx.LB_MULTIPLE:多選。
wx.LB_EXTENDED:多選,但是需要在按住Ctrl或Shift鍵時選擇項目。
wx.LB_SORT:對列表選擇項進行排序。
靜態圖片控件
靜態圖片控件用於顯示一張圖片,圖片可以是wx.Python所支持的任意圖片格式,靜態圖片控件類是wx.StaticBitmap。
在界面中實現兩個按鈕和一個靜態圖片控件,在單擊按鈕時顯示不同的圖片。
網絡通信
基本的網絡知識
TCP/IP
在網絡通信中會用到一些相關協議,其中,TCP/IP是非常重要的協議,由IP和TCP兩個協議構成。IP(Internet Protocol)是一種低級的路由協議,它將數據拆分在許多小的數據包中,並通過網絡將它們發送到某一特定地址,但無法保證所有包都抵達目的地,也不能保證包按順序抵達。
由於通過IP傳輸數據存在不安全性,所以還需要通過TCP(Transmission Control Protocol,傳輸控制協議)進行網絡通信。TCP是一種高層次的協議,是面向連接的可靠數據傳輸協議,如果有些數據包沒被收到,則會重發,對數據包的內容准確性進行檢查並保證數據包按順序抵達。所以,TCP能夠保證數據包安全地按照發送時的順序送達目的地。
IP地址
為了實現網絡中不同計算機之間的通信,每台計算機都必須有一個與眾不同的標識,這就是IP地址,TCP/IP使用IP地址來標識源地址和目的地址。
最初,所有的IP地址都是由32位數字構成的,由4個8位的二進制數組成,每8位之間用圓點隔開,例如192.168.1.1,這種類型的地址通過IPv4指定。現在有一種新的地址模式,叫作IPv6,IPv6使用128位數字表示一個地址。盡管IPv6比IPv4有很多優勢,但是由於習慣的問題,很多設備還是采用IPv4。
另外,我們有時還會用到一個特殊的IP地址127.0.0.1,127.0.0.1叫作回送地址,指本機。回送地址主要用於網絡軟件測試及本機的進程間通信,只發送數據,只進行本機進程間通信,不進行任何網絡傳輸。
端口
一個IP地址標識一台計算機,每一台計算機又有很多網絡通信程序在運行,提供網絡服務或進行通信,這就需要不同的端口進行通信。如果把IP地址比作電話號碼,那么端口就是分機號碼,在進行網絡通信時不僅要指定IP地址,還要指定端口號。
TCP/IP系統中的端口號是一個16位的數字,它的范圍是0~65535。將小於1024的端口號保留給預定義的服務,例如HTTP是80,FTP是21,Telnet是23,Email是25,等等。除非要和那些服務進行通信,否則不應該使用小於1024的端口。
HTTP/HTTPS
對互聯網的訪問大多基於HTTP/HTTPS,HTTP/HTTPS是TCP/IP的一種協議。
1 HTTP
HTTP(Hypertext Transfer Protocol,超文本傳輸協議)屬於應用層協議,其簡捷、快速的方式適用於分布式超文本信息傳輸。HTTP是無連接協議,即在每一次請求時都建立連接,服務器在處理完客戶端的請求后,會先應答客戶端,然后斷開連接,不會一直占用網絡資源。
HTTP/1.1共定義了8種請求方法:OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE和CONNECT。GET和POST方法最常用。
1)GET方法:用於向指定的資源發出請求,被發送的信息“顯式”地跟在URL后面。它一般只用於讀取數據,例如靜態圖片等。GET方法有點像使用明信片給別人寫信,將“信的內容”寫在外面,接觸到的人都可以看到,因此是不安全的。
2)POST方法:用於向指定的資源提交數據,請求服務器進行處理,例如提交表單或者上傳文件等。數據被包含在請求體中。POST方法像是把“信的內容”裝入信封中,接觸到該信封的人都看不到信的內容,因此是相對安全的。
2 HTTPS
HTTPS(Hypertext Transfer Protocol Secure,超文本傳輸安全協議)是超文本傳輸協議和SSL的組合,用於提供加密通信及對網絡服務器身份的鑒定。簡單地說,HTTPS是加密的HTTP。
HTTPS與HTTP的區別是:HTTPS使用https://代替http://,HTTPS使用端口443,而HTTP使用端口80與TCP/IP通信。
搭建自己的Web服務器
搭建Web服務器的步驟如下。
1 安裝JDK(Java開發工具包)
我們的Web服務器是Apache Tomcat,是支持Java Web技術的Web服務器。Apache Tomcat的運行需要Java運行環境,而JDK提供了Java運行環境,因此我們首先需要安裝JDK。
2 配置Java運行環境
Apache Tomcat在運行時需要用到JAVA_HOME環境變量,因此需要先設置JAVA_HOME環境變量。
首先,打開Windows系統環境變量設置對話框,打開該對話框有很多方式,如果是Windows 10系統,則在桌面上用鼠標右鍵單擊“此電腦”圖標,彈出Windows系統對話框,之后如下圖所示操作。
3 安裝Apache Tomcat服務器
我們可以從本章的配套代碼中找到Apache Tomcat安裝包apache-tomcat-9.0.13.zip,只需將apache-tomcat-9.0.13.zip解壓即可安裝Apache Tomcat服務器。
4 啟動Apache Tomcat服務器
在Apache Tomcat解壓目錄的bin目錄下找到startup.bat文件,雙擊startup.bat即可啟動Apache Tomcat。
啟動Apache Tomcat成功后會看到如下信息。
5 測試Apache Tomcat服務器
打開瀏覽器,在地址欄中輸入http://localhost:8080/NoteWebService/,在打開的頁面上介紹了當前Web服務器已經安裝的Web應用(NoteWebService)的具體使用方法。
打開瀏覽器,在地址欄中輸入網址http://localhost:8080/NoteWebService/note.do,在打開的頁面上可以查詢所有數據。
urllib.request模塊
發送GET請求
如果要發送HTTP/HTTPS的GET請求,則可以使用urllib.request模塊的Request對象。
示例:
發送POST請求
如果要發送HTTP/HTTPS的POST請求,則其發送流程與發送GET請求非常類似。
示例:
JSON數據
JSON文檔的結構
構成JSON文檔的兩種結構為:JSON對象(object)和JSON數組(array)。
1 JSON對象
JSON對象類似於Python中的字典類型。
2 JSON數組
JSON數組類似於Python中的列表類型,示例如下:
我們使用json模塊提供的loads(str)函數進行JSON數據的解碼,參數str是JSON字符串,返回Python數據。
JSON數據的解碼
JSON數據的解碼(decode)指將JSON數據轉換為Python數據,當從網絡中接收或從磁盤中讀取JSON數據時,需要將其解碼為Python數據。
在編碼過程中,JSON數據被轉換為Python數據。
示例:
下載圖片示例
在文件下載成功后,會在當前目錄下看到download.png文件。
訪問數據庫
如果數據量較少,則我們可以將數據保存到文件中;如果數據量較大,則我們可以將數據保存到數據庫中。
SQLite數據庫
SQLite是嵌入式系統使用的關系數據庫,目前的主流版本是SQLite 3。SQLite是開源的,采用C語言編寫而成,具有可移植性強、可靠性高、小而易用等特點。SQLite提供了對SQL-92標准的支持,支持多表、索引、事務、視圖和觸發。
SQLite數據類型
SQLite是無數據類型的數據庫,在創建表時不需要為字段指定數據類型。但從編程規范上講,我們應該指定數據類型,因為數據類型可以表明這個字段的含義,便於我們閱讀和理解代碼。
SQLite支持的常見數據類型如下。
INTEGER:有符號的整數類型。
REAL:浮點類型。
TEXT:字符串類型,采用UTF-8和UTF-16字符編碼。
BLOB:二進制大對象類型,能夠存放任意二進制數據。
Python數據類型與SQLite數據類型的映射
在使用Python訪問SQLite數據庫時,會經常涉及數據類型的互相轉換。它們的映射關系如下表所示。
使用GUI管理工具管理SQLite數據庫
1 安裝和啟動DB Browser for SQLite
從本章配套代碼中找到DB.Browser.for.SQLite-3.11.2-win32.zip安裝包文件,將該文件解壓到一個目錄中,在解壓目錄下找到DB Browserfor SQLite.exe文件,雙擊該文件即可啟動DB Browser for SQLite工具。
2 創建數據庫
一個SQLite數據庫對應一個SQLite數據文件,為了測試DB Browserfor SQLite工具,我們要先創建SQLite數據庫。
在上圖所示的界面單擊工具欄中的“新建數據庫”按鈕,彈出保存文件對話框。
3 創建數據表
在一個SQLite數據庫中可以包含多個數據表。在上圖所示的界面單擊“保存”按鈕,彈出建表對話框。
4 執行SQL語句
使用DB Browser for SQLite工具,可以執行任意合法的SQL語句。
5 瀏覽數據
DB Browser for SQLite常用於瀏覽數據。
數據庫編程的基本操作過程
數據庫編程主要分為兩類:查詢(Read)和修改(C插入、U更新、D刪除)。
1 查詢數據
查詢數據時需要6步,在查詢過程中需要提取數據結果集,最后釋放資源,即關閉游標和數據庫。
2 修改數據
修改數據時如上圖所示,最多需要6步,在修改過程中如果執行SQL操作成功,則提交數據庫事務;如果失敗,則回滾事務。最后釋放資源,關閉游標和數據庫。
sqlite3模塊API
Python官方提供了sqlite3模塊來訪問SQLite數據庫。
數據庫連接對象Connection
數據庫訪問的第一步是進行數據庫連接。
我們可以通過connect(database)函數建立數據庫連接,參數database是SQLite數據庫的文件路徑,如果連接成功,則返回數據庫連接對象Connection。
Connection對象有如下重要的方法。
close( ):關閉數據庫連接,在關閉之后再使用數據庫連接將引發異常。
commit( ):提交數據庫事務。
rollback( ):回滾數據庫事務。
cursor( ):獲得Cursor游標對象。
游標對象Cursor
一個Cursor游標對象表示一個數據庫游標,游標暫時保存了SQL操作所影響到的數據。游標是通過數據庫連接創建的。
游標Cursor對象有很多方法和屬性,其中的基本SQL操作方法如下。
execute(sql[,parameters]):執行一條SQL語句,sql是SQL語句,parameters是為SQL提供的參數,可以是序列或字典類型。返回值是整數,表示執行SQL語句影響的行數。
executemany(sql[,seq_of_params]):執行批量SQL語句,sql是SQL語句,seq_of_params是為SQL提供的參數,seq_of_params是序列。返回值是整數,表示執行SQL語句影響的行數。
在通過execute( )和executemany( )方法執行SQL查詢語句后,還要通過提取方法從查詢結果集中返回數據,相關提取方法如下。
fetchone( ):從結果集中返回只有一條記錄的序列,如果沒有數據,則返回None。
fetchmany(size=cursor.arraysize):從結果集中返回小於等於size記錄數的序列,如果沒有數據,則返回空序列,size在默認情況下是整個游標的行數。
fetchall( ):從結果集中返回所有數據。
數據庫的CRUD操作示例
對數據庫表中的數據可以進行4類操作:數據插入(Create)、數據查詢(Read)、數據更新(Update)和數據刪除(Delete),即增、刪、改、查。
示例中的數據表
為了查詢方便,我們預先插入幾條記錄。
在輸入SQL語句后,單擊該按鈕執行所有SQL語句
無條件查詢
SQL查詢語句是SELECT,根據是否帶有WHERE子句,分為:無條件查詢和有條件查詢,本節先介紹無條件查詢。
無條件查詢最為簡單,沒有WHERE子句。
示例:
有條件查詢
有條件查詢帶有WHERE子句,WHERE子句是查詢條件。
插入數據
數據插入操作SQL語句是INSERT。
示例:
數據插入成功,可以使用DB Browser for SQLite瀏覽數據。
更新數據
數據更新操作SQL語句是UPDATE。
示例:
數據更新成功,可以使用DB Browser for SQLite瀏覽數據。
刪除數據
數據刪除操作SQL語句是DELETE。
示例:
數據更新成功,可以使用DB Browser for SQLite瀏覽數據。
刪除數據
數據刪除操作SQL語句是DELETE。
示例:
數據更新成功,可以使用DB Browser for SQLite瀏覽數據。
多線程
如果想讓我們的程序同時執行多個任務,就需要使用多線程技術了。
線程相關的知識
進程
一個進程就是一個正在執行的程序,每一個進程都有自己獨立的一塊內存空間、一組系統資源。在進程的概念中,每一個進程的內部數據和狀態都是完全獨立的。
在Windows操作系統中,一個進程就是一個exe或者dll程序,它們相互獨立,相互也可以通信。
線程
在一個進程中可以包含多個線程,多個線程共享一塊內存空間和一組系統資源。所以,系統在各個線程之間切換時,開銷要比進程小得多,正因如此,線程被稱為輕量級進程。
主線程
Python程序至少有一個線程,這就是主線程,程序在啟動后由Python解釋器負責創建主線程,在程序結束后由Python解釋器負責停止主線程。
在多線程中,主線程負責其他線程的啟動、掛起、停止等操作。其他線程被稱為子線程。
線程模塊——threading
Python官方提供的threading模塊可以進行多線程編程。threading模塊提供了多線程編程的高級API,使用起來比較簡單。
在threading模塊中提供了線程類Thread,還提供了很多線程相關的函數,這些函數中常用的如下。
active_count( ):返回當前處於活動狀態的線程個數。
current_thread( ):返回當前的Thread對象。
main_thread( ):返回主線程對象。主線程是Python解釋器啟動的線程。
示例:
創建子線程
創建一個可執行的子線程,需要如下兩個要素。
1 線程對象:線程對象是threading模塊的線程類Thread或Thread子類所創建的對象。
2 線程體:線程體是子線程要執行的代碼,這些代碼會被封裝到一個函數中。子線程在啟動后會執行線程體。實現線程體主要有以下兩種方式。
1)自定義函數實現線程體。
2)自定義線程類實現線程體。
自定義函數實現線程體
創建線程Thread對象的構造方法如下:
target參數指向線程體函數,我們可以自定義該線程體函數;通過name參數可以設置線程名,如果省略這個參數,則系統會為其分配一個名稱;args是為線程體函數提供的參數,是一個元組類型。
示例:
自定義線程類實現線程體
另外一種實現線程體的方式是,創建一個Thread子類並重寫run( )方法,run( )方法就是線程體函數。
示例:
線程管理
線程管理包括線程創建、線程啟動、線程休眠、等待線程結束和線程停止,其中,線程創建、線程啟動和線程休眠在16.3節已經用到了,這些不再贅述。本節重點介紹等待線程結束和線程停止的內容。
等待線程結束
有時,一個線程(假設是主線程)需要等待另外一個線程(假設是t1子線程)執行結束才能繼續執行。
join( )方法的語法如下:
參數timeout用於設置超時時間,單位是秒。如果沒有設置timeout,則可以一直等待,直到結束。
示例:
從運行結果來看,在子線程t1結束后,主線程才輸出變量value的內容,這說明主線程被阻塞了。
如果嘗試將t1.join( )語句注釋掉,則輸出結果如下:
從運行結果可見,子線程t1還沒有結束,主線程就輸出變量value的內容了。
線程停止
在線程體結束時,線程就停止了。但在某些業務比較復雜時,會在線程體中執行一個“死循環”。線程體是否持續執行“死循環”是通過判斷停止變量實現的,“死循環”結束則線程體結束,線程也就結束了。
另外,在一般情況下,死循環會執行線程任務,然后休眠,再執行,再休眠,直到結束循環。
示例:
下載圖片示例
這個網絡爬蟲程序每隔一段時間都會執行一次下載圖片任務,在下載任務完成后,休眠一段時間再執行。這樣反復執行,直到爬蟲程序停止。
示例: