ویژگی تصویر

کتابخانه json در پایتون — معرفی جامع

  /  پایتون   /  کتابخانه json در پایتون
بنر تبلیغاتی الف

کتابخانهٔ استاندارد json در پایتون ابزاری ساده، سبک و متداول برای تبدیل داده‌های پایتون به رشتهٔ JSON و برعکس است. JSON (JavaScript Object Notation) فرمت متنیِ نسبتاً خوانایی است که در ارتباطات وب، ذخیره‌سازی پیکربندی و تبادل داده بین سرویس‌ها بسیار پرکاربرد است. در این مقاله به توابع اصلی، نکات عملی، نمونه‌های کد واقعی و تکنیک‌های پیشرفته می‌پردازیم.

توابع و کلاس‌های اصلی

تابع / کلاسکاربرد
json.dumpsتبدیل شی پایتون به رشتهٔ JSON
json.dumpنوشتن JSON در فایل
json.loadsتبدیل رشتهٔ JSON به شی پایتون
json.loadخواندن JSON از فایل
json.JSONEncoderسفارشی‌سازی سریال‌سازی
json.JSONDecoderسفارشی‌سازی دِسریال‌سازی

مثال پایه — خواندن و نوشتن JSON با UTF-8

import json

data = {
    "name": "علی",
    "age": 30,
    "skills": ["python", "django"]
}

# تبدیل به رشتهٔ JSON با حفظ یونیکد فارسی
json_str = json.dumps(data, ensure_ascii=False, indent=2)

# ذخیره در فایل با کدگذاری UTF-8
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

در این کد از ensure_ascii=False استفاده شده تا کاراکترهای غیرلاتین (مثلاً فارسی) به صورت خوانا در فایل ذخیره شوند. پارامتر indent برای زیبا سازی خروجی (pretty-print) است. هنگام بازخوانی کافی است از json.load یا json.loads استفاده کنید.

سریال‌سازی اشیاء سفارشی

ساختار JSON از انواع پایه‌ای پایتون مانند dict، list، str، int، float، bool و None پشتیبانی می‌کند. برای انواع دل‌خواه (مثلاً کلاس‌ها، datetime، Decimal یا set) نیاز به تبدیل دستی یا پیاده‌سازی JSONEncoder دارید.

import json
from dataclasses import dataclass
from datetime import datetime

@dataclass
class Person:
    name: str
    born: datetime

def person_encoder(obj):
    if isinstance(obj, Person):
        return {"__type__": "Person", "name": obj.name, "born": obj.born.isoformat()}
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Type {type(obj)} not serializable")

def person_decoder(d):
    if "__type__" in d and d["__type__"] == "Person":
        return Person(name=d["name"], born=datetime.fromisoformat(d["born"]))
    return d

p = Person("مریم", datetime(1990, 5, 17))
s = json.dumps(p, default=person_encoder, ensure_ascii=False)
obj = json.loads(s, object_hook=person_decoder)

در این مثال تابع default (اینجا person_encoder) به json.dumps می‌گوید که چگونه اشیاء نامأنوس را تبدیل کند. از object_hook در json.loads برای بازسازی شیٔ Person استفاده شده است. این الگو برای انواع پیچیده و تاریخ‌ها کاربردی و امن است.

نمونهٔ خطای متداول و راه‌حل

import json

data = {"items": {1, 2, 3}}  # set قابل سریال‌سازی مستقیم نیست
json.dumps(data)

این کد باعث TypeError می‌شود چون set به صورت پیش‌فرض سریال‌پذیر نیست. راه‌حل: تبدیل set به list یا استفاده از default برای سریال‌سازی آن:

json.dumps(data, default=lambda o: list(o) if isinstance(o, set) else TypeError())

بهترین روش متناسب با کاربردتان تعیین می‌شود: اگر ترتیب مهم نیست، list مناسب است. برای رفتارهای پیچیده‌تر از JSONEncoder سفارشی بهره ببرید.

بهینه‌سازی و نکات عملکردی

  • برای خروجی کامپکت از separators=(“,”, “:”) استفاده کنید تا فاصله‌های غیرضروری حذف شوند.
  • در پردازش داده‌های بسیار بزرگ از روش جریانی (streaming) با json.dump به همراه فایل باز و نوشتن مرحله‌ای استفاده کنید یا از کتابخانه‌هایی مثل ijson برای خواندن تَکه‌تَکه.
  • برای عملکرد بهتر در کاربردهای تجاری، از کتابخانه‌های سریع‌تر مانند orjson یا ujson استفاده کنید؛ اما مراقب تفاوت‌های سازگاری و گزینه‌ها باشید.
  • برای متون فارسی همیشه ensure_ascii=False و encoding=’utf-8′ در فایل را تنظیم کنید.
compact = json.dumps(data, separators=(",", ":"), ensure_ascii=False)

استفاده از separators خروجی را کوچک‌تر می‌کند (حذف فضاهای اضافی)، اینکار در انتقال شبکه یا ذخیره‌سازی حجم بالا مفید است.

کار با تاریخ‌ها و Decimal

پایتون datetime و Decimal به طور مستقیم سریال‌پذیر نیستند. معمولاً آنها را به رشتهٔ ISO یا عدد تبدیل می‌کنند:

import json
from datetime import datetime
from decimal import Decimal

def default(o):
    if isinstance(o, datetime):
        return o.isoformat()
    if isinstance(o, Decimal):
        return float(o)
    raise TypeError

data = {"t": datetime.now(), "price": Decimal("19.99")}
json.dumps(data, default=default, ensure_ascii=False)

تبدیل Decimal به float ممکن است دقت را کم کند؛ در صورت نیاز به دقت مالی بهتر است مقدار را به رشته تبدیل کنید و هنگام بارگذاری بازگردانید.

امنیت و خطاها

  • برخلاف بعضی روش‌ها، json.loads به‌طور پیش‌فرض eval یا exec اجرا نمی‌کند، اما همیشه ورودی‌های ناشناس را اعتبارسنجی کنید.
  • استفاده از object_hook و default باید با دقت باشد تا داده‌های مخرب باعث ایجاد اشیاء ناخواسته نشوند.
  • خطای رایج: JSONDecodeError هنگام خواندن فرمت نامناسب؛ استفاده از try/except برای مدیریت آن ضروری است.

موارد کاربردی و مثال‌های واقعی

  • ارسال/دریافت داده در APIs (REST) — تبدیل dict به JSON و برعکس.
  • فایل‌های پیکربندی سبک (config.json) — خواندن تنظیمات برنامه.
  • لاگ‌ها و ذخیرهٔ snapshot از وضعیت برنامه.
  • ارتباط بین سرویس‌های نوشته‌شده با زبان‌های مختلف.

جمع‌بندی و راهنمایی‌های عملی

کتابخانهٔ json پایتون برای بیشتر نیازها کافی و مناسب است. برای کاربردهای خاص: از ensure_ascii=False برای زبان‌های غیرلاتین استفاده کنید، با default و object_hook اشیاء پیچیده را مدیریت کنید، و برای داده‌های حجیم یا نیاز به سرعت بیشتر به گزینه‌هایی مثل orjson فکر کنید. همیشه ورودی‌ها را اعتبارسنجی کنید و هنگام سریال‌سازی دقت و سازگاری داده‌ها را رعایت کنید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: