《看漫畫學Python》學習筆記


封面

目錄

 

前言

  • “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的內容了。

線程停止

在線程體結束時,線程就停止了。但在某些業務比較復雜時,會在線程體中執行一個“死循環”。線程體是否持續執行“死循環”是通過判斷停止變量實現的,“死循環”結束則線程體結束,線程也就結束了。
另外,在一般情況下,死循環會執行線程任務,然后休眠,再執行,再休眠,直到結束循環。

示例:

下載圖片示例

這個網絡爬蟲程序每隔一段時間都會執行一次下載圖片任務,在下載任務完成后,休眠一段時間再執行。這樣反復執行,直到爬蟲程序停止。

示例:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM