Python 提供豐富的字串操作方法,從基本的索引切片到進階的正規表示式,都能有效處理文字資料。startswith、endswith 等方法簡化了字串比對,而 strip 和 split 則方便處理檔案格式,例如解析 /etc/fstab 設定。join 方法則能有效率地合併字串序列,避免中間儲存的效能損耗。正規表示式則提供更強大的模式匹配能力,結合 re 模組,可以處理複雜的字串搜尋、驗證和修改任務。理解正規表示式的基礎語法,例如字元類別、重複修飾符和分組,對於提升程式碼效率至關重要。此外,httpx 函式庫簡化了網頁 API 的互動,其內建的 JSON 序列化和反序列化功能,以及同步和非同步操作支援,使其成為自動化網頁操作的利器。使用顯式客戶端物件管理連線和設定引數,能提升程式碼的可維護性和彈性。最後,結合 RESTful API 的 CRUD 模型,能更有效率地操作網路資源。
字串處理與正規表示式
在 Python 中,字串是一種常見的資料型別,具有豐富的操作方法。除了基本的序列介面外,字串還有許多專屬的方法,特別是在文字分析方面非常有用。
字串索引與切片
Python 的字串支援索引和切片操作,可以方便地存取和操作字串中的字元。
a = "hello"
print(a[:-3]) # 輸出 'he'
print(a[::-1]) # 輸出 'olleh'
內容解密:
a[:-3]表示從字串a的開始到倒數第三個字元之前的切片,因此輸出'he'。a[::-1]表示以步長為 -1 的方式遍歷整個字串,實作了字串的反轉,因此輸出'olleh'。
字串方法
字串具有許多實用的方法,如 startswith、endswith、strip 和 split 等。
print("hello world".endswith("world")) # 輸出 True
print("hello world".endswith(("universe", "world"))) # 輸出 True
filename = "example.tar.gz"
print(filename.endswith((".tgz", ".tar.gz"))) # 檢查檔案是否具有特定的副檔名
內容解密:
endswith方法檢查字串是否以指定的字尾結尾,可以傳入單一字串或元組。- 在檢查檔案副檔名的例子中,傳入元組
(".tgz", ".tar.gz")以匹配多種可能的副檔名。
解析 /etc/fstab 檔案
下面是一個解析 /etc/fstab 檔案的例子,展示瞭如何使用 strip 和 split 方法。
with open("/etc/fstab") as fpin:
for line in fpin:
line = line.rstrip('\n')
line = line.split('#', 1)[0]
if not line:
continue
device, path, fstype, options, freq, passno = line.split()
print(f"Mounting {device} on {path}")
內容解密:
rstrip('\n')去除每行末尾的換行符。split('#', 1)[0]去除註解內容,只保留實際的設定行。split()用於按空白字元分割行內容,將其解析為各個欄位。- 使用格式化字串輸出結果,使其更易讀。
join 方法
join 方法用於將可迭代的字串物件連線起來。
print(' '.join(["hello", "world"])) # 輸出 "hello world"
names = dict(hello=1, world=2)
print(' '.join(names)) # 輸出 "hello world"
print('-*-'.join(str(x) for x in range(3))) # 輸出 "0-*-1-*-2"
內容解密:
' '.join(["hello", "world"])將列表中的字串以空格連線。- 對字典使用
join時,會將字典的鍵連線起來。 - 可以傳入生成器表示式,動態生成序列並連線,避免中間儲存。
正規表示式
正規表示式是一種用於描述字串模式的特殊語法,在 Python 中由 re 模組實作。
import re
pattern = re.compile(r"hello")
print(pattern.match("hello world")) # 匹配成功
內容解密:
- 使用
re.compile編譯正規表示式,生成一個模式物件。 - 可以使用該模式物件進行匹配、查詢和替換等操作。
正規表示式基礎
正規表示式的基本元素包括字元匹配、字元類別和重複修飾符。
import re
# 匹配 "hello"
pattern = re.compile(r"hello")
# 匹配 "hell" 後跟任意一個字元
pattern = re.compile(r"hell.")
# 匹配 "woman" 或 "women"
pattern = re.compile(r"wom[ae]n")
# 匹配任意數字
pattern = re.compile(r"[0-9]")
內容解密:
- 大多數字符代表其本身,如
hello匹配字串"hello"。 .代表任意一個字元。- 方括號
[]用於定義字元類別,如[0-9]匹配任意數字。 - 重複修飾符如
?、*和+用於指定前面的表示式重複的次數。
分組與非捕捉分組
正規表示式支援分組,可以用於捕捉匹配的部分或將部分表示式視為一個整體。
import re
# 使用非捕捉分組匹配 "hello-3" 或 "hello-world-5"
pattern = re.compile(r"(?:[a-z]{2,5}-){1,4}[0-9]")
內容解密:
(?:...)表示非捕捉分組,將括號內的表示式視為一個整體,但不捕捉匹配結果。- 該模式匹配特定的格式,如
"hello-3"或"hello-world-5"。
正規表示式與JSON資料處理
正規表示式是一種強大的字串處理工具,廣泛應用於文字搜尋、驗證和修改等任務中。Python的re模組提供了正規表示式的支援,使得開發者能夠以程式化的方式處理複雜的字串模式。
正規表示式的基本概念
正規表示式是一種特殊的字串,用於描述或匹配一系列符合特定規則的字串。它們可以用來檢查一個字串是否包含某種特定的子字串,或者用來從字串中提取符合特定模式的子字串。
建立正規表示式物件
在Python中,首先需要使用re.compile()函式將一個正規表示式模式編譯成一個正規表示式物件。
import re
reobj = re.compile('ab+a')
搜尋與匹配
正規表示式物件提供了match()和search()兩種方法來進行字串的匹配。match()方法檢查字串的開頭是否符合模式,而search()方法則在整個字串中搜尋第一個符合模式的子字串。
m = reobj.search('hello abba world')
print(m.group()) # 輸出:abba
分組與命名分組
正規表示式支援分組(grouping),可以捕捉符合模式的子字串。透過使用括號(),可以定義分組,並在匹配後提取這些分組。
reobj = re.compile('(a)(b+)(a)')
m = reobj.search('hello abba world')
print(m.group(1)) # 輸出:a
print(m.group(2)) # 輸出:bb
print(m.group(3)) # 輸出:a
詳細解說:
(a):第一個分組,匹配字元a。(b+):第二個分組,匹配一個或多個字元b。(a):第三個分組,再次匹配字元a。
此外,還可以為分組命名,以提高程式碼的可讀性。
reobj = re.compile('(?P<prefix>a)(?P<body>b+)(?P<suffix>a)')
m = reobj.search('hello abba world')
print(m.group('prefix')) # 輸出:a
print(m.group('body')) # 輸出:bb
print(m.group('suffix')) # 輸出:a
詳細解說:
(?P<prefix>a):命名為prefix的分組,匹配字元a。(?P<body>b+):命名為body的分組,匹配一個或多個字元b。(?P<suffix>a):命名為suffix的分組,匹配字元a。
正規表示式的詳細模式
使用re.VERBOSE旗標,可以在正規表示式中加入空白和註解,使其更易讀。
reobj = re.compile(r"""
(?P<prefix>a) # 起始字元,總是一個 a
(?P<body>b+) # 中間部分,可以是任意數量的 b
(?P<suffix>a) # 結尾字元,總是一個 a
""", re.VERBOSE)
m = reobj.search("hello abba world")
print(m.groups()) # 輸出:('a', 'bb', 'a')
詳細解說:
(?P<prefix>a):匹配起始字元a。(?P<body>b+):匹配中間的一個或多個字元b。(?P<suffix>a):匹配結尾字元a。
JSON資料處理
JSON(JavaScript Object Notation)是一種輕量級的資料交換格式,易於閱讀和編寫,也易於機器解析和生成。Python的json模組提供了JSON資料的編碼和解碼功能。
JSON基本操作
使用json.dumps()函式可以將Python物件轉換為JSON格式的字串,而json.loads()函式則可以將JSON格式的字串解析為Python物件。
import json
thing = [{"hello": 1, "world": 2}, None, True]
json_str = json.dumps(thing)
print(json_str) # 輸出:[{"hello": 1, "world": 2}, null, true]
loaded_thing = json.loads(json_str)
print(loaded_thing) # 輸出:[{'hello': 1, 'world': 2}, None, True]
詳細解說:
thing:一個包含字典、None和True的Python列表。json.dumps(thing):將Python物件轉換為JSON格式的字串。json.loads(json_str):將JSON格式的字串解析回Python物件。
JSON美化輸出
使用json.dumps()函式的額外引數,可以美化JSON輸出的格式,使其更易讀。
print(json.dumps(loaded_thing, indent=4, sort_keys=True))
詳細解說:
indent=4:設定縮排為4個空格,使輸出更易讀。sort_keys=True:按鍵排序輸出,使輸出更有序。
HTTPX:自動化網頁API的強大工具
許多系統都提供根據網頁的API,而httpx函式庫正是為了自動化這些API而設計的。它不僅易於使用,還具備許多強大的功能。
為何選擇HTTPX?
httpx不支援Python 2,如果您仍在使用Python 2,請考慮升級至較新的版本,因為Python 2已經不再接收安全性更新。- 相較於Python標準函式庫中的HTTP客戶端設施,使用
httpx幾乎總是更好的選擇。它支援彈性的身份驗證、內部序列化和反序列化JSON,並支援同步和非同步操作。 httpx與流行的requests函式庫高度相容。除非您使用了requests中的特殊功能,如特殊的憑證驗證,否則將使用requests的程式碼轉換為使用httpx只需要更改匯入陳述式。
使用客戶端
在httpx中,建議使用明確的客戶端。雖然可以直接使用httpx.get/httpx.post等函式,但這實際上是在使用全域的客戶端物件。
import httpx
# 不建議這樣使用
response = httpx.get('https://example.com')
# 建議使用明確的客戶端
client = httpx.Client()
response = client.get('https://example.com')
為什麼要使用明確的客戶端?
- 避免全域可變分享狀態:使用全域客戶端物件可能會導致難以診斷的錯誤,例如當連線到使用cookie的網站時,不同的部分程式碼可能會覆寫彼此的cookie。
- 便於單元測試:使用明確的客戶端可以更容易地進行模擬,從而簡化單元測試。
- 存取更多功能:某些功能僅在使用明確的客戶端物件時才可存取,例如新增追蹤標頭或自定義使用者代理。
HTTPX的強大功能
- JSON序列化和反序列化:
httpx可以自動處理JSON資料的序列化和反序列化。 - 同步和非同步操作:
httpx支援同步和非同步操作,可以根據您的需求選擇合適的操作方式。 - 彈性身份驗證:
httpx提供了彈性的身份驗證機制,可以輕鬆處理不同的身份驗證需求。
程式碼範例
import httpx
def fetch_data(url):
with httpx.Client() as client:
response = client.get(url)
response.raise_for_status() # 如果HTTP請求傳回了不成功的狀態碼,則引發HTTPError
return response.json()
#### 內容解密:
1. 我們首先匯入了`httpx`模組,這是Python中用於處理HTTP請求的現代函式庫。
2. `fetch_data`函式接受一個URL作為引數,並使用`httpx.Client()`建立一個HTTP客戶端。
3. 使用`client.get(url)`傳送GET請求到指定的URL。
4. `response.raise_for_status()`用於檢查HTTP請求是否成功。如果傳回的狀態碼表示請求失敗(4xx或5xx),則會引發`HTTPError`。
5. 如果請求成功,則使用`response.json()`解析回應內容為JSON格式,並將其傳回。
data = fetch_data('https://api.example.com/data')
print(data)
使用顯式客戶端物件的重要性
在撰寫預期長期維護的程式碼時,使用顯式客戶端物件(Client object)是更好的選擇。這樣做的原因在於,將客戶端物件的初始化與主要邏輯分離,能夠使程式碼更具彈性與可維護性。
為什麼要使用顯式客戶端物件?
使用 httpx.Client() 建立客戶端物件後,所有與 HTTP 請求相關的操作都應透過該物件進行。客戶端物件提供了 .get()、.put()、.post()、.patch() 和 .options() 等方法,涵蓋了常見的 HTTP 請求操作。
客戶端物件作為上下文管理器
客戶端物件可以作為上下文管理器使用,這樣能夠確保在上下文結束時,所有待處理的連線都會被清理。這對於有嚴格使用限制的伺服器尤其重要。
with httpx.Client() as c:
c.get(...)
避免依賴 Python 的參照計數
依賴 Python 的參照計數來關閉連線是危險的。Python 語言並不保證這種行為,而且在某些實作(如 PyPy)中,這種行為並不成立。此外,一些小細節(如客戶端被捕捉為堆積疊追蹤中的區域性變數)就可能阻止參照計數機制正常運作,導致連線長時間未被關閉。
設定客戶端物件的引數
客戶端物件支援多個建構子引數,用於設定請求的預設行為。其中最常用的引數包括:
auth=:用於設定驗證資訊。headers=:用於設定預設的請求標頭。
設定 User-Agent
在測試 Web API 時,在 User-Agent 中加入識別字串是非常有用的。這樣可以透過伺服器日誌區分哪些請求來自測試程式碼。
client = httpx.Client(
headers={'User-Agent': 'Python/MySoftware ' + __version__}
)
Cookie 管理與客戶端憑證
客戶端物件內部維護了一個 CookieJar,可以透過 Client(cookies=cookie_jar) 建構子引數進行設定。這對於需要持久化 Cookie 的場景非常有用,例如實作可重新啟動的 HTTP 會話。
此外,客戶端物件也支援設定客戶端憑證,用於需要憑證驗證的場景。
REST 簡介
REST(Representational State Transfer)是一種鬆散且廣泛應用的網路資源表示標準。它常用於將資料函式庫結構直接對映到 Web 上,此時常被稱為 CRUD 模型(Create, Retrieve, Update, Delete)。
RESTful 操作與 HTTP 方法
- Create:通常使用
POST方法實作。 - Retrieve:使用
GET方法實作,大多數情況下是唯讀且安全的。 - Update:可以使用
PUT(完整更新)或PATCH(部分更新)方法實作。 - Delete:使用
DELETE方法實作。
使用 httpx 進行 RESTful 操作
httpx 函式庫對 JSON 有特殊的支援,可以方便地進行 JSON 資料的編碼與解碼。
>>> resp = c.put("https://httpbin.org/put", json=dict(hello=5, world=2))
>>> resp.json()['json']
{'hello': 5, 'world': 2}
REST API 的典型用法
一個良好的 REST API 會在回應中包含資源識別符(URL),這些 URL 可以用於進一步的操作。
>>> res = c.get("https://api.github.com/repos/python/cpython/pulls")
>>> commits_url = res.json()[0]['commits_url']
>>> commits = c.get(commits_url).json()
>>> commits[0]['commit']['message'][:40]
'bpo-46104: Fix example broken by GH-3014'