Python 入門指南 5.0
單元 21 - 非同步程式設計與認識標準程式庫
Python 已經內建大多數常用的功能,更多的功能都放在標準程式庫 (standard library) 裡
⇣
More
下表列出官方 Library Reference 整理的所有模組 (module) 分類
分類 | 說明 |
---|---|
Built-in Functions | 介紹所有內建函數。 |
Built-in Constants | 介紹所有內建常數,包括 False 、 True 、 None 等。 |
Built-in Types | 介紹所有內建型態及真假值計算,內建型態包括 int 、 float 、 complex 、迭代器、 list 、 tuple 、 range 、 str 、 bytes 、 bytearray 、 memoryview 、 set 、 frozenset 、 dict 及內容管理員、模組、類別、函數、方法等型態,真假值計算包括真值測試及布林運算等。 |
Built-in Exceptions | 介紹所有內建的例外類別。 |
Text Processing Services | 介紹文字相關處理模組,包括 string 、 re 、 difflib 、 textwrap 、 unicodedata 、 stringprep 、 readline 、 rlcompleter 等。 |
Binary Data Services | 介紹二進位資料處理模組,包括 struct 、 codecs 等。 |
Data Types | 介紹各種處理資料的資料型態模組,包括 datetime 、 zoneinfo 、 calendar 、 collections 、 collections.abc 、 heapq 、 bisect 、 array 、 weakref 、 types 、 copy 、 pprint 、 reprlib 、 enum 、 graphlib 等。 |
Numeric and Mathematical Modules | 介紹處理數字資料的模組,包括 numbers 、 math 、 cmath 、 decimal 、 fractions 、 random 、 statistics 等。 |
Functional Programming Modules | 介紹函數式程式設計相關模組,包括 itertools 、 functools 、 operator 等。 |
File and Directory Access | 介紹檔案及目錄處理的模組,包括 pathlib 、 os.path 、 fileinput 、 stat 、 filecmp 、 tempfile 、 glob 、 fnmatch 、 linecache 、 shutil 等。 |
Data Persistence | 介紹儲存資料相關模組,包括 pickle 、 copyreg 、 shelve 、 marshal 、 dbm 、 sqlite3 等。 |
Data Compression and Archiving | 介紹資料壓縮相關模組,包括 zlib 、 gzip 、 bz2 、 lzma 、 zipfile 、 tarfile 等。 |
File Formats | 介紹檔案格式相關模組,包括 csv 、 configparser 、 tomllib 、 netrc 、 plistlib 等。 |
Cryptographic Services | 介紹密碼處理相關模組,包括 hashlib 、 hmac 、 secrets 等。 |
Generic Operating System Services | 介紹一般作業系統相關模組,包括 os 、 io 、 time 、 argparse 、 getopt 、 logging 、 logging.config 、 logging.handlers 、 getpass 、 curses 、 curses.textpad 、 curses.ascii 、 curses.panel 、 platform 、 errno 、 ctypes 等。 |
Concurrent Execution | 介紹並行計算相關模組,包括 threading 、 multiprocessing 、 multiprocessing.shared_memory 、 concurrent 、 concurrent.futures 、 subprocess 、 sched 、 queue 、 contextvars 、 _thread 等。 |
Networking and Interprocess Communication | 介紹行程間通訊及網路處理相關模組,包括 asyncio 、 socket 、 ssl 、 select 、 selectors 、 signal 、 mmap 等。 |
Internet Data Handling | 介紹網路資料處理相關模組,包括 email 、 json 、 mailbox 、 mimetypes 、 base64 、 binascii 、 quopri 等。 |
Structured Markup Processing Tools | 介紹結構化標記處理工具,包括 html 、 html.parser 、 html.entities 、 xml 、 xml.etree.ElementTree 、 xml.dom 、 xml.dom.minidom 、 xml.dom.pulldom 、 xml.sax 、 xml.sax.handler 、 xml.sax.saxutils 、 xml.sax.xmlreader 、 xml.parsers.expat 等。 |
Internet Protocols and Support | 介紹對網路協定的支援,包括 webbrowser 、 wsgiref 、 urllib 、 urllib.request 、 urllib.response 、 urllib.parse 、 urllib.error 、 urllib.robotparser 、 http 、 http.client 、 ftplib 、 poplib 、 imaplib 、 smtplib 、 uuid 、 socketserver 、 http.server 、 http.cookies 、 http.cookiejar 、 xmlrpc 、 xmlrpc.client 、 xmlrpc.server 、 ipaddress 等。 |
Multimedia Services | 介紹多媒體相關模組,包括 wave 、 colorsys 等。 |
Internationalization | 介紹國際化相關模組,包括 gettext 、 locale 等。 |
Program Frameworks | 介紹程式框架相關模組,包括 turtle 、 cmd 、 shlex 等。 |
Graphical User Interfaces with Tk | 介紹圖形應用的 Tk 模組,包括 tkinter 、 tkinter.colorchooser 、 tkinter.font 、 tkinter.simpledialog 、 tkinter.messagebox 、 tkinter.scrolledtext 、 tkinter.dnd 、 tkinter.ttk 、 tkinter.tix 等。 |
Development Tools | 介紹程式發展相關工具,包括 typing 、 pydoc 、 doctest 、 unittest 、 unittest.mock 、 unittest.mock 、 2to3 、 test 、 test.support 、 test.support.socket_helper 、 test.support.script_helper 、 test.support.bytecode_helper 、 test.support.threading_helper 、 test.support.os_helper 、 test.support.import_helper 、 test.support.warnings_helper 等。 |
Debugging and Profiling | 介紹除錯及效能分析相關模組,包括 bdb 、 faulthandler 、 pdb 、 cProfile 、 profile 、 timeit 、 trace 、 tracemalloc 等。 |
Software Packaging and Distribution | 介紹軟體套件及發佈相關工具,包括 distutils 、 ensurepip 、 venv 、 zipapp 等。 |
Python Runtime Services | 介紹執行期間相關服務,包括 sys 、 sysconfig 、 builtins 、 __main__ 、 warnings 、 dataclasses 、 contextlib 、 abc 、 atexit 、 traceback 、 __future__ 、 gc 、 inspect 、 site 等。 |
Custom Python Interpreters | 介紹直譯器相關工具,包括 code 、 codeop 。 |
Importing Modules | 介紹引入模組相關工具,包括 zipimport 、 pkgutil 、 modulefinder 、 runpy 、 importlib 、 importlib.resources 、 importlib.resources.abc 、 importlib.metadata 、 sys.path 等。 |
Python Language Services | 介紹 Python 語言相關工具,包括 ast 、 symtable 、 token 、 keyword 、 tokenize 、 tabnanny 、 pyclbr 、 py_compile 、 compileall 、 dis 、 pickletools 等。 |
MS Windows Specific Services | MS-Windows 特定服務,包括 msvcrt 、 winreg 、 winsound 。 |
Unix Specific Services | UNIX 特定服務,包括 posix 、 pwd 、 grp 、 termios 、 tty 、 pty 、 fcntl 、 resource 、 syslog 。 |
每個模組都有為數不等的類別 (class) 、函數 (function) 、常數 (constant) 等定義,需要時可以直接用關鍵字 (keyword) import 引入到自己的程式中使用。
這裡先介紹關鍵字 async 與 await 會用到的 asyncio 模組,主要用在非同步程式設計 (asynchronous programming) 方面,雖然說非同步程式設計的複雜對初學者會有有些複雜,下面我們盡可能以初學者能理解的方式來解釋。
基本上,程式執行的時候是按照程式檔案,從上而下一行程式碼接著一行程式碼去執行,這時候會一直佔用 CPU 資源,但是有時候程式沒辦法及時處理,像是連到某一個網站要求資料,必須等網站回傳資料,如果網站伺服器計算需要時間,這時候我們的程式就會一直佔用 CPU 資源,直到網站回傳資料。
非同步程式設計就是在程式中告訴作業系統,這邊的程式需要等待, CPU 資源可以先分配給其他程式使用,這樣作業系統就會合理去使用 CPU 資源,進而提高程式運作的效率。
下面用個簡單例子來說明需要等待跟不需要等待的差別
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # 引入標準程式庫中的 asyncio
import asyncio
# 定義協程函數
async def main():
# 等待一秒
await asyncio.sleep(1)
# 顯示提示訊息
print("未輸入...")
# 取得使用者輸入的迴圈
while True:
# 取得使用者輸入
user = input("請輸入:")
# 迴圈結束條件
if user == "quit":
break
# 判斷使用者是否有輸入
if user:
# 印出使用者輸入
print(user)
else:
# 等待一秒印出提示訊息
asyncio.run(main())
# 檔名: std_demo01.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
|
處理非同步程式設計,要先在第 2 行引入標準程式庫中的 asyncio
2 | import asyncio
|
然後要定義協程 (coroutine) 函數
5 7 9 | async def main():
await asyncio.sleep(1)
print("未輸入...")
|
協程函數是在關鍵字 def 之前加上 async
5 | async def main():
|
然後在協程函數中加入關鍵字 await , await 後面接的是可能需要等待的程式碼,這裡用的是 asyncio.sleep(1) ,表示會睡眠一秒
9 | await asyncio.sleep(1)
|
也就是說,程式告訴作業系統,在程式睡眠一秒的時間內,作意系統可以把這一秒的 CPU 資源分配給其他程式使用。
協程函數最底下是印出「未輸入」的提示訊息
7 | print("未輸入...")
|
然後下面是用一個典型 while True 迴圈 (loop) 來取得使用者輸入
12 14 16 17 19 21 22 24 | while True:
user = input("請輸入:")
if user == "quit":
break
if user:
print(user)
else:
asyncio.run(main())
|
第 14 行利用內建函數 input() 取得使用者輸入
14 | user = input("請輸入:")
|
input() 的參數 (parameter) 為印出的提示訊息,這裡也就是提示在冒號後進行輸入,然後輸入的內容會以字串 (string) 形式指派到變數 (variable) user 中,其實 input() 函數就是一個會一直佔用 CPU 資源的函數, input() 會一直等到使用者按下 Enter 鍵才會結束。
接下來判斷使用者是否輸入 quit ,如果使用者輸入 quit 就會中斷 while True 迴圈,等同結束程式執行
16 17 | if user == "quit":
break
|
然後判斷使用者是否有輸入,如果使用者按下鍵盤上除了 Enter 之外的按鍵, user 就會有值,回傳 True ,底下會印出使用者輸入
19 21 | if user:
print(user)
|
反倒如果使用者直接按下 Enter 鍵, input() 就會直接回傳空字串,空字串回傳 False ,因此會跳到 else 的部分去執行協程函數 main()
22 24 | else:
asyncio.run(main())
|
執行這個程式,一開始就是無限等待使用者輸入
$ python std_demo01.py |
請輸入: █ |
使用者輸入文字,按下 Enter 鍵就會在下一行顯示使用者輸入的文字
請輸入: Hello |
Hello |
請輸入: █ |
如果直接按下 Enter 鍵,就會進入 main() 等待一秒
請輸入: |
█ |
接著印出提示訊息,接者跳回輸入提示
未輸入... |
請輸入: █ |
必須打入 quit 才能讓程式正常結束
請輸入: quit |
$ |
以上的例子就是 input() 會持續佔用 CPU 資源等待使用者按下鍵盤上的按鍵,協程函數 main() 會自動睡眠一秒,這一秒期間並不佔用 CPU 資源。
接下來繼續看到幾個標準程式庫中的例子,基本上所有內建識別字 (identifier) 都屬於標準程式庫的定義,例如內建型態跟內建函數,說到內建函數,其中我們最常用到的 print() ,第一個參數是不限個數參數的序對 (tuple) ,也就是可以輸入任意個數的參數值,另外還有關鍵字引數 (keyword argument) sep 及 end 。
sep 的預設值是空格 " " ,至於 end 的預設值則是斷行符號 "\n" ,以下舉一個例子,利用 input 輸入得到 number ,然後在 print() 印出來
1 2 3 4 5 6 7 8 9 10 11 12 | # 使用者輸入
number = int(input("請輸入:"))
# 印出使用者輸入
print(number, number, sep="...", end="..")
print(number, end=".")
print(number)
# 檔名: std_demo02.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
|
第 4 行,第一次使用 print() 是印出兩個 number ,中間以 "..." 分隔,結尾則是 ".."
4 | print(number, number, sep="...", end="..")
|
第 5 行,第二次使用 print() 印出一個 number ,並且以 "." 結尾
5 | print(number, end=".")
|
第 6 行,第三次使用 print() 印出一個 number ,沒有設定 end 所以預設印出 "\n"
6 | print(number)
|
由於第三次呼叫 print() 才印出 "\n" ,因此所有內容會印在同一行
$ python std_demo02.py |
請輸入:12 |
12...12..12.12 |
$ |
datetime 是標準程式庫中處理時間日期的模組,以下程式示範印出現在時間
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # 從標準程式庫 datetime 引入 datetime
from datetime import datetime
# 取得現在時間
now = datetime.now()
# 格式化現在時間字串
now_str = str(now.hour) + ":" + str(now.minute) + ":" + str(now.second)
# 印出現在時間
print(now_str)
# 檔名: std_demo03.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
|
先從 datetime 引入 datetime
2 | print(number)
|
datetime 是處理日期時間的物件。
利用 datetime 的 now() 會回傳現在的日期時間物件
5 | now = datetime.now()
|
然後利用 hour 、 minute 及 second 屬性 (attribute) 組成以冒號區隔的時間字串
7 | now_str = str(now.hour) + ":" + str(now.minute) + ":" + str(now.second)
|
最後印出時間字串
9 | print(now_str)
|
執行結果如下
$ python std_demo03.py |
11:26:58 |
$ |
最後我們介紹關鍵字 with , with 主要用在輸入輸出的部分,舉例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 計數變數
count = 1
# 進行檔案寫入
with open('demo.txt', 'w') as f:
# 依次寫入第幾行
while count < 6:
s = "第" + str(count) + "行\n"
f.write(s)
count += 1
# 進行檔案讀取
with open('demo.txt', 'r') as f:
# 依次印出檔案中的每一行
for s in f.readlines():
print(s, end="")
# 檔名: std_demo04.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
|
第 4 行先用 with 搭配內建函數 open() 開啟檔案,注意這裡 open() 第一個參數為檔案名稱,第二個參數是模式, 'w' 表示寫入
4 | with open('demo.txt', 'w') as f:
|
關鍵字 as 後面接的是變數名稱,這裡採用 f ,意思是說利用 open() 開啟 demo.txt 檔案,模式是寫入,因此如果沒有這個檔案就會建立這個檔案,結果變數 f 會連結到 open() 回傳的檔案物件, with 底下縮排的程式碼就是進行檔案處理
6 7 8 9 | while count < 6:
s = "第" + str(count) + "行\n"
f.write(s)
count += 1
|
這段檔案處理的程式碼的重點在第八行
8 | f.write(s)
|
檔案物件的 write() 將參數字串寫入到檔案之中,由於字串結尾都已加入段行符號 "\n" ,因此一次寫入就是一行,這裡一共會寫入五行。
關鍵字 with 其實是處理輸入輸出的語法糖,因為處理輸入輸出要先建立輸入輸出的物件,最後處理完畢要用 close() 關閉輸入輸出物件,用 with 的好處是會自動關閉,我們就不需要考慮是否關閉的問題。
底下第二個 with 則是重新開啟 demo.txt ,模式 'r' 表示讀取
11 13 14 | with open('demo.txt', 'r') as f:
for s in f.readlines():
print(s, end="")
|
然後利用檔案物件的 readlines() 方法印出檔案中的每一行內容,執行結果如下
$ python std_demo04.py |
第1行 |
第2行 |
第3行 |
第4行 |
第5行 |
$ |
基礎篇至此把 Python 所有關鍵字都簡略介紹用法,接下來我們開始介紹用 Python 開發軟體的方式,帶領讀者開發 GUI 的編密碼軟體,藉此介紹更多的 Python 寫程式技巧囉!
中英文術語對照 | |
---|---|
非同步程式設計 | asynchronous programming |
屬性 | attribute |
類別 | class |
協程 | coroutine |
常數 | constant |
函數 | function |
識別字 | identifier |
關鍵字 | keyword |
關鍵字引數 | keyword argument |
迴圈 | loop |
參數 | parameter |
模組 | module |
標準程式庫 | standard library |
字串 | string |
序對 | tuple |
變數 | variable |
重點整理 |
---|
1. Python 的標準程式庫中有非常多常用功能,自己寫程式的時候可以直接引入使用。 |
2. 非同步程式設計是不持續佔用 CPU 資源的程式設計模式。 |
3. 內建識別字都屬於標準程式庫的定義。 |
4. 內建函數 pinrt() 可以接受多個參數,其中可以用關鍵字引數 sep 設定參數的分隔方式, end 設定最後結尾符號。 |
5. 標準程式庫中的 datetime 用來處理時間、日期。 |
6. 關鍵字 with 可用來進行輸入輸出的工作,內建函數 open() 可用來開啟檔案。 |
問題與討論 |
---|
1. 為甚麼要有標準程式庫?程式要什麼功能不能全部自己開發嗎? |
2. 什麼是協程函數? |
3. 檔案處理可以不用關鍵字 with 嗎?用 with 有什麼方便的地方? |
練習 |
---|
1. 標準程式庫中的 re 用來處理正規運算式,寫一個程式 exercise2101.py ,利用 re 的 search() 來尋找英文句子中是否存在 no 。 參考程式碼 |
2. 標準程式庫中的 calendar 可以顯示月曆,寫一個程式 exercise2102.py ,先設定星期天為一個星期的第一天,然後印出月曆。 參考程式碼 |
3. 標準程式庫中的 math 有很多跟數學相關的常數及函數,寫一個程式 exercise2103.py ,利用 math 中的 gcd() 計算參數的最大公因數,然後再利用 isqrt() 判斷參數是否為平方,最後印出 pi 值。 參考程式碼 |
4. 標準程式庫中的 decimal 用來處理浮點數精確度的問題,寫一個程式 exercise2104.py ,利用 decimal 中的 Decimal 印出 3.14 、 0.1 、 11.0 等浮點數。 參考程式碼 |
5. 標準程式庫中的 random 用來處理擬隨機數,寫一個程式 exercise2105.py ,利用 random 中的 randint() 印出 0 到 9 、 10 到 19 、 20 到 29 之間的隨機整數。 參考程式碼 |
6. 標準程式庫中有兩種判斷現在作業系統的方式,分別是利用 os 中的 name 及 sys 中的 platform ,寫一個程式 exercise2106.py ,在命令列中印出這兩個常數值。 參考程式碼 |
7. 標準程式庫中的 os 用來處理跟作業系統有關的項目,寫一個程式 exercise2107.py ,利用 os 中的 getcwd() 取得現在的命令列路徑。 參考程式碼 |
8. 標準程式庫中的 doctest 可以在文件字串中寫測試程式,然後放在執行部分進行測試,寫一個程式 exercise2108.py ,利用之前寫過的練習加入具有測試程式碼的文件字串,然後在執行部分利用 doctest 的 testmod() 進行測試。 參考程式碼 |
9. 標準程式庫中的 unittest 可以做單元測試,寫一個程式 exercise2109.py ,引入上題的定義,然後定義繼承自 unittest 中 TestCase 的測試類別,執行部分呼叫 unittest 的 main() 。 參考程式碼 |
10. 標準程式庫中的 sys 有許多根直譯器相關的功能,寫一個程式 exercise2110.py ,利用 sys 的 maxsize 取得直譯器能處理的最大整數值, version 取得現在的直譯器版本, getsizeof() 計算參數所所佔的記憶體位元組數。 參考程式碼 |