返回文章列表

Python 資料序列化:JSON、Pickle 與 Shelve 深度解析

本文探討 Python 中常用的序列化方法:JSON、Pickle 和 Shelve,分析它們的特性、優缺點和適用場景,幫助開發者根據專案需求選擇最佳方案。同時,文章也提供實際程式碼範例,演示如何在 Python 中使用這些序列化工具,以及如何處理序列化過程中可能遇到的問題,例如中文編碼和安全性風險。

Web 開發 資料科學

Python 提供了多種序列化工具,讓開發者能將程式中的物件轉換成可儲存或傳輸的格式。瞭解這些工具的特性,才能在專案中做出最佳選擇。本文將探討 JSON、Pickle 和 Shelve,分析它們的優缺點及適用場景。JSON 是一種輕量級的資料交換格式,易於閱讀、編寫,也易於機器解析和生成。它根據 JavaScript 語法,但獨立於程式語言,成為 Web API 和資料儲存的常用格式。Python 的 json 模組提供了方便的 API,用於在 Python 物件和 JSON 字串之間進行轉換。使用時要注意資料的編碼問題,尤其是有非 ASCII 字元時,ensure_ascii=False 可確保中文字元正確顯示。JSON 的優點是易於閱讀和編寫、跨平台、跨語言,與支援度廣泛,缺點是僅支援基本資料型別,無法序列化複雜的 Python 物件,安全性也較低。Pickle 是 Python 內建模組,能將 Python 物件序列化為二進位格式,儲存到檔案中,可以儲存類別、函式,甚至是程式的狀態,非常適合儲存訓練好的機器學習模型。使用 pickle.dump() 序列化物件並寫入檔案,pickle.load() 從檔案讀取並反序列化。Pickle 的優點是可以序列化幾乎所有 Python 物件,使用簡單方便,缺點是二進位格式可讀性差,跨語言相容性差,與存在安全性風險,強烈建議只反序列化信任來源的資料。Shelve 模組建立在 Pickle 之上,提供簡單的鍵值對儲存方式,可將 Python 物件持久化到磁碟,類別似持久化的字典。使用 shelve.open() 開啟 shelve 檔案,像操作字典一樣儲存和讀取資料。Shelve 的優點是使用簡單,方便持久化 Python 物件,缺點是根據 Pickle 存在安全風險,不適合高併發應用,與檔案大小可能隨資料增長而變大。

檔案時間魔法:Python 讀取、轉換與時區處理

在日常開發中,讀取檔案的建立、修改和存取時間是常見的需求。Python 提供了豐富的模組來處理這些時間資訊,讓開發者能夠輕鬆地進行時間戳轉換、時區調整等操作。玄貓將分享如何使用 ostimedatetimepytz 模組,讓檔案時間處理變得更加靈活。

時間戳記:檔案的時光膠囊

檔案的每個動作都會留下時間的痕跡,這些痕跡以時間戳記的形式儲存。時間戳記是一個數值,代表從 epoch(通常是 1970 年 1 月 1 日午夜)到特定時間點的秒數。

Python 的 os 模組提供方法來取得這些時間戳記:

  • os.path.getctime(file_path): 取得檔案的建立時間。
  • os.path.getmtime(file_path): 取得檔案的最後修改時間。
  • os.path.getatime(file_path): 取得檔案的最後存取時間。
import os
import time

file_path = '/path/to/file.txt'

# 取得檔案建立時間
creation_time = os.path.getctime(file_path)
creation_time = time.localtime(creation_time)
print("建立時間:", time.strftime("%Y-%m-%d %H:%M:%S", creation_time))

# 取得檔案修改時間
modification_time = os.path.getmtime(file_path)
modification_time = time.localtime(modification_time)
print("修改時間:", time.strftime("%Y-%m-%d %H:%M:%S", modification_time))

# 取得檔案存取時間
access_time = os.path.getatime(file_path)
access_time = time.localtime(access_time)
print("存取時間:", time.strftime("%Y-%m-%d %H:%M:%S", access_time))

內容解密

  • os.path.getctime()os.path.getmtime()os.path.getatime() 函式分別用於取得檔案的建立、修改和存取時間戳記。
  • time.localtime() 函式將時間戳記轉換為本地時間的 time 結構。
  • time.strftime() 函式用於格式化時間結構,將其轉換為易於閱讀的字串。

時間格式轉換:開發客製化時光儀錶板

時間戳記是給機器看的,但人類更喜歡易讀的時間格式。strftime() 函式讓我們可以將時間轉換為各種格式:

import os
import time

file_path = '/path/to/file.txt'

# 取得檔案修改時間
modification_time = os.path.getmtime(file_path)
modification_time = time.localtime(modification_time)

# 轉換為 ISO 格式
modification_time_str = time.strftime("%Y-%m-%d %H:%M:%S", modification_time)
print("修改時間 (ISO):", modification_time_str)

# 轉換為自定義格式
modification_time_str = time.strftime("%b %d, %Y %I:%M:%S %p", modification_time)
print("修改時間 (自定義):", modification_time_str)

內容解密

  • %Y: 年份(四位數)
  • %m: 月份(01-12)
  • %d: 日期(01-31)
  • %H: 小時(00-23)
  • %M: 分鐘(00-59)
  • %S: 秒數(00-59)
  • %b: 月份簡寫(Jan, Feb, …)
  • %I: 小時(01-12)
  • %p: AM 或 PM

時間間隔計算:timedelta 的妙用

timedelta 類別可以表示時間的長度,讓我們可以進行時間的加減運算。

from datetime import datetime, timedelta
import os

file_path = '/path/to/file.txt'

# 取得檔案修改時間
modification_time = datetime.fromtimestamp(os.path.getmtime(file_path))

# 取得目前時間
current_time = datetime.now()

# 計算時間間隔
time_interval = current_time - modification_time
print("時間間隔:", time_interval)

# 加減時間
new_time = current_time + timedelta(days=1)
print("明天:", new_time)

new_time = current_time - timedelta(hours=1)
print("一小時前:", new_time)

# 格式化時間間隔
time_interval = timedelta(hours=1, minutes=30, seconds=45)
time_interval_str = str(time_interval)
print("時間間隔:", time_interval_str)

內容解密

  • datetime.fromtimestamp() 將時間戳記轉換為 datetime 物件。
  • datetime.now() 取得目前的 datetime 物件。
  • timedelta(days=1) 建立一個表示一天的 timedelta 物件。
  • str(time_interval)timedelta 物件轉換為字串。

時區轉換:pytz 讓時間無國界

在處理跨時區的檔案時,pytz 是一個強大的工具,可以確保時間轉換的準確性。

from datetime import datetime
import pytz

# 建立一個 datetime 物件,表示原始時區的時間
original_time = datetime(2023, 3, 17, 15, 30)

# 轉換時區
original_timezone = pytz.timezone('America/New_York')
new_timezone = pytz.timezone('Europe/London')

new_time = original_timezone.localize(original_time).astimezone(new_timezone)

print("原始時間:", original_time)
print("轉換後時間:", new_time)

內容解密

  • pytz.timezone('America/New_York') 建立一個表示紐約時區的時區物件。
  • original_timezone.localize(original_time) 將原始時間本地化為紐約時區。
  • astimezone(new_timezone) 將時間轉換為倫敦時區。

透過 ostimedatetimepytz 模組的靈活運用,玄貓可以輕鬆地讀取、轉換和處理檔案的時間資訊,讓時間在程式中不再是難題。

時間魔法:Python 檔案操作中的時區與資料持久化

在資料處理的世界裡,時間和資料的儲存是兩個不可或缺的要素。Python 提供了強大的工具,如 pytzdateutil 處理時區轉換,以及 json 模組進行資料序列化與持久化。讓玄貓帶領大家深入瞭解如何在檔案操作中運用這些工具,確保時間的精確性和資料的可靠性。

時區處理:pytz 的妙用

時區處理是讓許多開發者頭痛的問題,尤其是在處理跨國資料或需要精確時間戳記的應用中。pytz 模組提供了一個全面的時區資料函式庫,讓時區轉換變得輕鬆可靠。

from datetime import datetime
import pytz

# 建立一個 datetime 物件,表示原始時區的時間
original_time = datetime(2023, 3, 12, 2, 30)

# 設定原始時區和目標時區
original_timezone = pytz.timezone('America/New_York')
new_timezone = pytz.timezone('Europe/London')

# 將 datetime 物件本地化到原始時區,並轉換為目標時區
new_time = original_timezone.localize(original_time, is_dst=None).astimezone(new_timezone)

print("原始時間:", original_time)
print("轉換後時間:", new_time)

內容解密

  1. 首先,我們匯入了 datetimepytz 模組。
  2. original_time 變數儲存了一個 datetime 物件,代表紐約時間 2023-03-12 02:30:00
  3. original_timezonenew_timezone 變數分別設定為紐約和倫敦的時區。
  4. localize() 方法將 original_time 物件本地化到紐約時區。is_dst=None 引數表示讓 pytz 自動判斷是否為日光節約時間。
  5. astimezone() 方法將本地化後的 datetime 物件轉換為倫敦時區。
  6. 最後,我們印出原始時間和轉換後的時間。

pytz 的強大之處在於它能正確處理日光節約時間 (Daylight Saving Time, DST) 的轉換。透過 is_dst=None 引數,pytz 會自動判斷時間是否落在 DST 轉換期間,並進行相應的調整。

更彈性的日期處理:dateutil

除了 pytzdateutil 也是一個處理日期時間的利器。它提供了更靈活的日期時間字串解析和日期運算功能。

from datetime import datetime
from dateutil.parser import parse
from dateutil.relativedelta import relativedelta

# 解析 ISO 8601 格式的日期字串
date_string = '2023-03-17'
date = parse(date_string)
print("解析後的日期:", date)

# 取得目前時間
now = datetime.now()

# 加上一週
one_week_from_now = now + relativedelta(weeks=1)
print("目前時間:", now)
print("一週後:", one_week_from_now)

內容解密

  1. 我們匯入了 datetimeparserelativedelta
  2. parse() 函式將 ISO 8601 格式的日期字串 "2023-03-17" 解析為 datetime 物件。
  3. datetime.now() 取得目前的日期和時間。
  4. relativedelta(weeks=1) 建立一個表示「一週」的時間差物件。
  5. now 加上 relativedelta(weeks=1),即可得到一週後的日期和時間。

dateutil 讓日期時間的解析和運算變得更加直觀和方便。無論是處理各種格式的日期字串,還是進行複雜的日期加減,dateutil 都能輕鬆應對。

資料持久化:json 的簡潔之道

資料序列化是將 Python 物件轉換為可儲存或傳輸的格式。json 模組提供了一種簡單與廣泛使用的資料序列化方式。

import json

# 建立一個 Python 字典
person = {"name": "John", "age": 30, "city": "New York"}

# 將字典序列化為 JSON 字串
json_string = json.dumps(person)
print(json_string)

# 將字典序列化為 JSON 並寫入檔案
with open("person.json", "w") as f:
    json.dump(person, f)

# 從 JSON 字串反序列化為 Python 物件
person = json.loads(json_string)
print(person)

# 從 JSON 檔案反序列化為 Python 物件
with open("person.json", "r") as f:
    person = json.load(f)
print(person)

內容解密

  1. json.dumps() 函式將 Python 字典 person 序列化為 JSON 格式的字串。
  2. json.dump() 函式將 Python 字典 person 序列化為 JSON 格式,並寫入名為 "person.json" 的檔案中。
  3. json.loads() 函式將 JSON 格式的字串反序列化為 Python 字典。
  4. json.load() 函式從 "person.json" 檔案讀取 JSON 格式的資料,並反序列化為 Python 字典。

json 格式簡潔易讀,與被廣泛支援,因此成為資料持久化的理想選擇。透過 json 模組,我們可以輕鬆地將 Python 物件儲存到檔案中,並在需要時讀取出來。

總結來說,pytzdateutiljson 是 Python 檔案操作中不可或缺的工具。它們分別負責處理時區轉換、日期時間解析和資料序列化,讓玄貓在處理時間和資料時更加得心應手。掌握這些工具,能讓你的 Python 程式更加健壯和可靠。

Python資料持久化攻略:JSON、Pickle、Shelve與DBM的深度解析

在資料科學與軟體工程的世界中,如何有效地儲存和讀取資料至關重要。Python提供了多種序列化(Serialization)工具,讓開發者能將程式中的物件轉換為可儲存或傳輸的格式。本文將探討JSON、Pickle、Shelve和DBM這四種常見的序列化方法,分析它們的優缺點及適用場景,助您在專案中做出最佳選擇。

JSON:輕量級資料交換的標準

JSON(JavaScript Object Notation)是一種輕量級的資料交換格式,易於閱讀和編寫,也易於機器解析和生成。它根據JavaScript語法,但獨立於程式語言,成為Web API和資料儲存的常用格式。

玄貓小提示: 在處理JSON資料時,務必注意資料的編碼問題,特別是當資料包含非ASCII字元時。

Python與JSON:json模組的使用

Python的json模組提供了方便的API,用於在Python物件和JSON字串之間進行轉換。

import json

# Python字典
data = {
    "name": "玄貓",
    "age": 30,
    "city": "台北"
}

# 序列化為JSON
json_string = json.dumps(data, ensure_ascii=False) # ensure_ascii=False 處理中文
print(json_string)

# JSON反序列化為Python物件
loaded_data = json.loads(json_string)
print(loaded_data)

內容解密:

  • json.dumps(): 將Python物件序列化為JSON字串。ensure_ascii=False 確保中文字元能正確顯示。
  • json.loads(): 將JSON字串反序列化為Python物件。

JSON的優缺點

  • 優點
    • 易於閱讀和編寫
    • 跨平台、跨語言
    • 廣泛的支援度
  • 缺點
    • 僅支援基本資料型別(字串、數字、布林值、列表、字典)
    • 無法序列化複雜的Python物件(例如:類別例項)
    • 安全性較低,可能存在注入風險

Pickle:Python物件的完全儲存

pickle是Python內建模組,能將Python物件序列化為二進位格式,並將其儲存到檔案中。這意味著你可以儲存Python的類別、函式,甚至是程式的狀態。

玄貓經驗分享: 在為某個機器學習專案設計資料儲存方案時,我發現pickle非常適合儲存訓練好的模型,因為它可以完整儲存模型的結構和引數。

Pickle的使用範例

import pickle

# 定義一個類別
class Person:
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city

    def __str__(self):
        return f"{self.name} ({self.age}) from {self.city}"

# 建立一個Person物件
person = Person("玄貓", 30, "台北")

# 序列化到檔案
with open("person.pickle", "wb") as f:
    pickle.dump(person, f)

# 從檔案反序列化
with open("person.pickle", "rb") as f:
    loaded_person = pickle.load(f)

print(loaded_person)

內容解密:

  • pickle.dump(object, file): 將Python物件序列化並寫入檔案。"wb"表示以二進位寫入模式開啟檔案。
  • pickle.load(file): 從檔案讀取序列化的資料並反序列化為Python物件。"rb"表示以二進位讀取模式開啟檔案。

Pickle的優缺點

  • 優點
    • 可以序列化幾乎所有的Python物件
    • 使用簡單方便
  • 缺點
    • 二進位格式,可讀性差
    • 跨語言相容性差
    • 安全性風險高:反序列化惡意pickle資料可能執行任意程式碼。強烈建議只反序列化來自信任來源的資料!

Shelve:物件持久化的簡易方案

shelve模組建立在pickle之上,提供了一個簡單的鍵值對儲存方式,可以將Python物件持久化到磁碟。你可以把它想像成一個持久化的字典。

Shelve的使用範例

import shelve

# 建立或開啟一個shelve檔案
with shelve.open("my_shelf") as shelf:
    # 儲存資料
    shelf["name"] = "玄貓"
    shelf["age"] = 30
    shelf["city"] = "台北"

# 讀取資料
with shelve.open("my_shelf") as shelf:
    name = shelf["name"]
    age = shelf["age"]
    print(name, age)

內容解密:

  • shelve.open(filename): 開啟一個shelve檔案。如果檔案不存在,則建立一個新的檔案。
  • shelf[key] = value: 將資料儲存到shelve檔案中,就像操作字典一樣。

Shelve的優缺點

  • 優點
    • 使用簡單,類別似字典操作
    • 方便地持久化Python物件
  • 缺點
    • 根據pickle,存在相同的安全風險
    • 不適合高併發的應用場景
    • 檔案大小可能隨著資料的增長而變得很大

DBM:輕量級資料函式庫的選擇

dbm(Database Manager)是Python中用於操作類別Unix DBM資料函式庫的模組。它提供了一種簡單的方式來儲存和檢索字串鍵值對,適用於小型資料的持久化儲存。

DBM使用範例

import dbm

# 建立或開啟DBM資料函式庫
with dbm.open('my_db', 'c') as db:
    # 儲存資料 (鍵和值都必須是bytes)
    db[b'name'] = b'BlackCat'
    db[b'age'] = b'30']

    # 檢索資料
    name = db[b'name']
    age = db[b'age']

    print(name.decode('utf-8'), age.decode('utf-8'))

內容解密:

  • dbm.open('my_db', 'c'): 開啟或建立DBM資料函式庫檔案。'c' 模式表示如果資料函式庫不存在則建立。
  • 鍵和值都必須是位元組字串(bytes),因此需要使用 b'...' 定義。
  • 從資料函式庫中檢索到的值也是位元組字串,需要使用 .decode('utf-8') 解碼為字串。

DBM的優缺點

  • 優點:
    • 簡單易用,適合儲存小型資料。
    • 不需要額外的伺服器或設定。
  • 缺點:
    • 僅支援字串鍵值對,不支援複雜資料結構。
    • 功能較為有限,不適合大型或複雜的應用。
    • 不同的DBM實作(如dbm.gnudbm.ndbm)可能在不同系統上有不同的行為。

如何選擇?

選擇哪種序列化方法取決於你的具體需求:

  • JSON: 適合於需要跨平台、跨語言交換資料的場景,例如Web API。
  • Pickle: 適合於儲存Python物件,但要注意安全性風險。
  • Shelve: 適合於簡單的物件持久化,但不適合高併發應用。
  • DBM: 適合小型、簡單的字串鍵值對儲存,不需要複雜的資料結構。

在實際應用中,玄貓建議根據資料的複雜度、安全需求和效能要求,綜合考慮各種方案,選擇最適合的序列化方法。