Python 套件介紹 - smart_open 不僅聰明還很好用
Posted on Feb 12, 2022 in Python 模組/套件推薦 by Amo Chen ‐ 3 min read
現今後端(backend)儲存解決方案相較於以往多了許多選擇,從傳統的硬碟儲存到現代各式各樣的雲端儲存服務,例如 AWS S3, Google Cloud Storage, Azure Blob Storage 甚至 HDFS(Hadoop Distributed File System) 等等,因此開發過程不免都會遇到需要整合雲端儲存方案的問題,與其重新發明輪胎,不如選擇 1 套簡單易用而且通吃各家服務的套件,不僅省事還能有效增加開發效率。
所以,你需要 smart_open 的幫忙!
本文環境
- Python 3.7
- smart_open 5.2.1
$ pip install smart_open==5.2.1
smart_open 簡介
smart_open 可以視為 Python 內建 open() 函式的替代品,不僅 100% 相容,還更加強大,只要 from smart_open import open
取代 Python 內建的 open() 就能夠與 AWS S3, Google Cloud Storage, Azure Blob Storage 甚至 HDFS(Hadoop Distributed File System) 等儲存服務無縫接軌。
以下 smart_open
讀檔的範例,完全與 Python 內建 open() 函式使用方式一致,因此不用擔心使用 smart_open
需要改寫既有程式的問題。
from smart_open import open
with open('/etc/hosts', 'r') as file:
for line in file:
print(line)
支援自動壓縮(compress)/解壓縮(decompress)
以往用 Python 寫入 gzip 壓縮檔(副檔名 .gz
),會使用類似以下的程式碼進行:
import gzip
import shutil
# 以 gzip 方法壓縮檔案
with open('/home/user/file.txt', 'rb') as f_in:
with gzip.open('/home/user/file.gz', 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
或者使用 gzip 模組讀取 gzip 壓縮檔內容:
import gzip
# 讀取 gzip 壓縮檔
with gzip.open('/home/user/file.gz', 'rb') as f:
file_content = f.read()
使用 gzip 模組寫入內容到 gzip 壓縮檔中:
import gzip
# 寫入資料到 gzip 壓縮檔
content = b'content here'
with gzip.open('/home/user/file.gz', 'wb') as f:
f.write(content)
改用 smart_open
之後,都只要使用 open() 即可, smart_open
會自行偵測副檔名(file extension)推測壓縮方式,並結合 mode 參數判斷要自動進行壓縮或解壓縮,所以前述 gzip 相關的程式碼都可以簡化為:
from smart_open import open
# 讀取 gzip 檔
with open('/home/user/file.gz', 'rb') as f:
file_content = f.read()
# 寫入 gzip 檔
content = b'content here'
with open('/home/user/file.gz', 'wb') as f:
f.write(content)
目前 smart_open
支援 .bz2
與 .gz
2 種副檔名的自動壓縮/解壓縮,如果你的檔案使用 bzip2
與 gzip
壓縮,但是副檔名不是 .bz2
或 .gz
, 可以呼叫 open() 時指定 compression
參數(參數值為 .bz2
或 .gz
),指名要使用何種壓縮/解壓縮方式:
from smart_open import open
# 讀取 gzip 檔
with open('/home/user/file.gz', 'rb', compression='.gz') as f:
file_content = f.read()
# 寫入 gzip 檔
content = b'content here'
with open('/home/user/file.gz', 'wb', compression='.gz') as f:
f.write(content)
如果檔案使用的是其他壓縮方式,也可以使用 register_compressor() 註冊其處理方式,以下是官方文件所提供的 register_compressor() 註冊 LZMA 壓縮方式的範例程式:
import lzma, os
from smart_open import open, register_compressor
def _handle_xz(file_obj, mode):
return lzma.LZMAFile(filename=file_obj, mode=mode, format=lzma.FORMAT_XZ)
register_compressor('.xz', _handle_xz)
with open('smart_open/tests/test_data/1984.txt.xz') as fin:
print(fin.read(32))
各式儲存服務整合
smart_open
最方便的是其整合多家雲端儲存方案,諸如:
- Amazon S3
- Google Cloud Storage
- Azure Blob Storage
以 Amazon S3 為例(需安裝 boto3 ),只要設定必要的環境變數(environment variables),例如 AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
等等(詳見 Boto3 官方文件 ), smart_open
就會自動以 boto3 建立 S3 client 並透過 boto3 所提供的 API 與 S3 進行互動,接著你的 open() 就能夠直接讀取/寫入 S3 服務,例如官方所提供的範例:
from smart_open import open
with open('s3://commoncrawl/robots.txt', 'rb') as s3_object:
for line in s3_object:
print(line)
除了讓 smart_open
自動幫忙建立 S3 client 之外, smart_open
也提供 transport_params
參數讓開發者可以帶入自己建立的 boto3 S3 client:
import boto3
from smart_open import open
with open(
's3://commoncrawl/robots.txt', 'rb',
transport_params={
'client': boto3.client('s3'),
}
) as s3_object:
for line in s3_object:
print(line)
此外, smart_open
預設使用 S3 的 multipart upload, 可以將檔案切分成多個小區塊分開上傳,如此不僅可以改善傳輸效率與穩定度,也能在遭遇網路問題(network issue)導致上傳失敗時,僅重新傳送失敗的部分即可,很適合用來傳輸大檔案(例如檔案大小超過 100MB),但如果使用情境是上傳小檔案的話,可以關掉 multipart upload:
import boto3
from smart_open import open
with open(
's3://<your S3 bucket>/<your object key>', 'wb',
transport_params={
'multipart_upload': False,
}
) as s3_object:
for line in s3_object:
print(line)
以上是關於 Amazon S3 的部分,至於 Azure 以及 Google Cloud Storage 詳情請見 smart_open
的 README 或者 Github repo 內的原始碼,基本上使用方法大同小異。
除了各家雲端儲存服務之外, smart_open
也支援以 HDFS(Hadoop Distributed File System), SSH, SFTP, SCP(Secure Copy Protocol) 等協定(protocol)進行讀寫檔案,因此可以在 URI(Uniform Resource Identifier) 上指定用前述協定存取檔案,也就是說 open() 也接受以下形式的路徑,真的十分方便:
hdfs://path/file
webhdfs://host:port/path/file
ssh://username@host/path/file
ssh://username:password@host/path/file
scp://username@host/path/file
scp://username:password@host/path/file
sftp://username@host/path/file
sftp://username:password@host/path/file
總結
以上就是關於 smart_open 的介紹,這麼好用的套件,還不快點導入到你的 Python 專案之中!
Happy coding!
References
https://github.com/RaRe-Technologies/smart_open