非同步程式碼已成為 Python 開發的支柱。隨著 asyncio 成為標準函式庫的一部分,而許多第三方軟體包提供與其相容的功能,這種範例不會很快消失。
如果您正在編寫非同步程式碼,請務必確保程式碼的所有部分都能協同工作,這樣其中的一個方面就不會減慢其他所有部分的速度。文件 I/O 可能是這方面的常見阻礙,因此讓我們逐步了解如何使用 aiofiles 庫非同步處理文件。
從基礎開始,這是非同步讀取檔案內容所需的所有程式碼(在非同步函數內):
async with aiofiles.open('filename', mode='r') as f: contents = await f.read() print(contents)
讓我們繼續深入挖掘。
您可能會聽到「非同步」、「非阻塞」或「並發」等術語,但對它們的含義感到有點困惑。根據這個更詳細的教程,兩個主要屬性是:
因此,非同步程式碼是可以在等待結果時掛起的程式碼,以便讓其他程式碼同時執行。它不會“阻止”其他程式碼運行,因此我們可以將其稱為“非阻塞”程式碼。
asyncio 程式庫為 Python 開發人員提供了多種工具來執行此操作,aiofiles 提供了更具體的檔案處理功能。
在我們開始之前,請確保您已設定好 Python 環境。如果您需要協助,請按照本指南的 virtualenv 部分進行操作。如果您有多個專案在同一台電腦上運行,那麼讓一切正常運作,特別是在虛擬環境方面,對於隔離依賴項非常重要。 您至少需要 Python 3.7 或更高版本才能運行本文中的程式碼。
現在您的環境已經設定完畢,您將需要安裝一些第三方函式庫。我們將使用 aiofiles,因此在啟動虛擬環境後使用以下命令安裝它:
pip install aiofiles==0.6.0
對於本文其餘部分的範例,我們將使用與原始 150 個 Pokemon 相對應的 Pokemon API 資料的 JSON 檔案。您可以在此處下載包含所有這些內容的資料夾。有了這個,您應該準備好繼續編寫一些程式碼。
首先,我們簡單地開啟一個與特定 Pokemon 對應的文件,將其 JSON 解析為字典,並印出其名稱:
async with aiofiles.open('filename', mode='r') as f: contents = await f.read() print(contents)
運行此程式碼時,您應該會看到“articuno”列印到終端。您也可以逐行非同步迭代檔案(此程式碼將列印出 articuno.json 的所有 9271 行):
pip install aiofiles==0.6.0
寫入檔案也類似標準 Python 檔案 I/O。假設我們想要建立包含每個神奇寶貝可以學習的所有動作清單的檔案。舉個簡單的例子,以下是我們對 Pokemon Ditto 所做的事情,它只能學習「變形」這個招式:
import aiofiles import asyncio import json async def main(): async with aiofiles.open('articuno.json', mode='r') as f: contents = await f.read() pokemon = json.loads(contents) print(pokemon['name']) asyncio.run(main())
讓我們用一個有不只一個動作的神奇寶貝來嘗試這個,例如雷頓:
import aiofiles import asyncio async def main(): async with aiofiles.open('articuno.json', mode='r') as f: async for line in f: print(line) asyncio.run(main())
如果您開啟 rhydon_moves.txt,您應該會看到一個包含 112 行的文件,其開頭類似。
現在讓我們變得更複雜一點,對我們擁有 JSON 檔案的所有 150 個 Pokemon 執行此操作。我們的程式碼必須讀取每個文件,解析 JSON,並將每個 Pokemon 的動作重寫到一個新文件:
import aiofiles import asyncio async def main(): async with aiofiles.open('ditto_moves.txt', mode='w') as f: await f.write('transform') asyncio.run(main())
運行此程式碼後,您應該會看到 Pokemon 檔案的目錄,其中包含 .txt 檔案和 .json 文件,其中包含與每個 Pokemon 對應的移動清單。
如果您需要執行一些非同步操作,並希望以與這些非同步任務相對應的資料結束,例如在寫入檔案後列出每個 Pokemon 的動作列表,您可以使用 asyncio.ensure_future 和 asyncio.gather。
您可以將處理每個檔案的程式碼部分分解為自己的非同步函數,並將這些函數呼叫的承諾附加到任務清單中。以下是函數的範例,以及您的新主函數的外觀:
import aiofiles import asyncio import json async def main(): # Read the contents of the json file. async with aiofiles.open('rhydon.json', mode='r') as f: contents = await f.read() # Load it into a dictionary and create a list of moves. pokemon = json.loads(contents) name = pokemon['name'] moves = [move['move']['name'] for move in pokemon['moves']] # Open a new file to write the list of moves into. async with aiofiles.open(f'{name}_moves.txt', mode='w') as f: await f.write('\n'.join(moves)) asyncio.run(main())
這是在 Python 中使用非同步程式碼的常見方法,通常用於發出 HTTP 請求之類的事情。
本文中使用 Pokemon 資料的範例只是展示 aiofiles 模組功能以及如何編寫程式碼來導航檔案目錄以進行讀寫的藉口。希望您可以根據您要解決的特定問題調整這些程式碼範例,以便檔案 I/O 不會成為非同步程式碼中的障礙。
我們只觸及了 aiohttp 和 asyncio 功能的皮毛,但我希望這能讓您更輕鬆地開始進入非同步 Python 世界。
我期待看到您建造的內容。請隨時與我們聯繫並分享您的經驗或提出任何問題。
以上是使用 aiofiles 和 asyncio 在 Python 中非同步處理文件的詳細內容。更多資訊請關注PHP中文網其他相關文章!