JSON إلى Python Dataclass
توليد Python dataclasses من JSON
إدخال JSON
مخرجات Python
ما هو تحويل JSON إلى Python Dataclass؟
يأخذ تحويل JSON إلى Python dataclass كائن JSON خامًا وينتج مجموعة من تعريفات Python dataclass مع تعليقات أنواع دقيقة. تولّد وحدة dataclasses في Python، المُقدَّمة في PEP 557 (Python 3.7)، توابع __init__ و__repr__ و__eq__ تلقائيًا من حقول الكلاس الموصوفة بالأنواع. عندما تعمل مع واجهات API من JSON أو ملفات إعداد أو طوابير رسائل، تمنح dataclasses بياناتك بنية مكتوبة بالأنواع يمكن لمحررات الكود ومدققي الأنواع مثل mypy التحقق منها أثناء التطوير.
تُعيد json.loads() في Python قواميس وقوائم عادية. وهي تؤدي الغرض، لكنها لا تحمل أي معلومات عن الأنواع: مفتاح مكتوب بشكل خاطئ يُعيد None بدلًا من إطلاق استثناء، ولا يستطيع محررك إكمال أسماء الحقول تلقائيًا. تحل dataclasses هذه المشكلة بتعيين كل مفتاح JSON إلى حقل مسمى ذي نوع محدد. تصبح كائنات JSON المتداخلة تعريفات dataclass منفصلة، وتصبح المصفوفات تعليقات List[T]، وتصبح القيم الفارغة Optional[T] مع قيمة افتراضية None.
كتابة هذه التعريفات يدويًا عمل روتيني مضنٍ. عليك قراءة JSON واستنتاج نوع كل حقل من قيمته وتحويل المفاتيح من camelCase أو snake_case إلى اصطلاحات Python والتعامل مع الحالات الاستثنائية مثل الحقول القابلة للإلغاء والمصفوفات ذات الأنواع المختلطة. يؤدي المحوّل كل هذا في أجزاء من الثانية. تلصق JSON وتحصل على كود dataclass صحيح وتكمل عملك.
لماذا تستخدم محوّل JSON إلى Python؟
ترجمة بنى JSON إلى تعريفات كلاسات Python يدويًا تعني تخمين الأنواع من بيانات نموذجية، وإعادة ترتيب الحقول لتأتي الإلزامية قبل الاختيارية، وتحديث كل شيء عند تغير الـAPI. يزيل المحوّل هذا الاحتكاك.
حالات استخدام تحويل JSON إلى Python
جدول تعيين أنواع JSON إلى Python
كل قيمة JSON تتعيّن على تعليق نوع Python محدد. يوضح الجدول أدناه كيف يُترجم المحوّل كل نوع JSON، مع صياغة وحدة typing (Python 3.7+) والصياغة المدمجة المتاحة من Python 3.10 فصاعدًا.
| نوع JSON | مثال | Python (typing) | Python 3.10+ |
|---|---|---|---|
| string | "hello" | str | str |
| number (integer) | 42 | int | int |
| number (float) | 3.14 | float | float |
| boolean | true | bool | bool |
| null | null | Optional[str] | str | None |
| object | {"k": "v"} | @dataclass class | nested model |
| array of strings | ["a", "b"] | List[str] | list[str] |
| array of objects | [{"id": 1}] | List[Item] | list[Item] |
| mixed array | [1, "a"] | List[Any] | list[Any] |
مرجع مزيّن Dataclass
يقبل المزيّن @dataclass عدة معامِلات تغيّر سلوك الكلاس المولَّد. يغطي هذا المرجع الخيارات الأكثر صلة عند العمل مع بيانات مستنتجة من JSON.
| المزيّن / الحقل | السلوك | متى تستخدمه |
|---|---|---|
| @dataclass | Generates __init__, __repr__, __eq__ from field annotations | Standard dataclasses |
| @dataclass(frozen=True) | Makes instances immutable (hashable, no attribute reassignment) | Config objects, dict keys |
| @dataclass(slots=True) | Uses __slots__ for lower memory and faster attribute access | Python 3.10+, large datasets |
| @dataclass(kw_only=True) | All fields require keyword arguments in __init__ | Python 3.10+, many fields |
| field(default_factory=list) | Sets a mutable default without sharing state between instances | List/dict/set defaults |
dataclass مقابل Pydantic مقابل TypedDict
تقدم Python ثلاث طرق شائعة لتعريف بنى موصوفة بالأنواع من JSON. كل طريقة تناسب حالة استخدام مختلفة. dataclasses هي خيار المكتبة القياسية بدون أي تبعيات. يُضيف Pydantic التحقق أثناء التشغيل. يُعلّق TypedDict القواميس العادية بالأنواع دون إنشاء كلاس جديد.
أمثلة برمجية
تُظهر هذه الأمثلة كيفية استخدام dataclasses المولَّدة في Python، وكيفية توليدها برمجيًا من JavaScript، وكيفية استخدام أساليب بديلة مثل Pydantic وأدوات سطر الأوامر.
from dataclasses import dataclass
from typing import List, Optional
import json
@dataclass
class Address:
street: str
city: str
zip: str
@dataclass
class User:
id: int
name: str
email: str
active: bool
score: float
address: Address
tags: List[str]
metadata: Optional[str] = None
raw = '{"id":1,"name":"Alice","email":"alice@example.com","active":true,"score":98.5,"address":{"street":"123 Main St","city":"Springfield","zip":"12345"},"tags":["admin","user"],"metadata":null}'
data = json.loads(raw)
# Reconstruct nested objects manually
addr = Address(**data["address"])
user = User(**{**data, "address": addr})
print(user.name) # -> Alice
print(user.address) # -> Address(street='123 Main St', city='Springfield', zip='12345')// Minimal JSON-to-Python-dataclass generator in JS
function jsonToPython(obj, name = "Root") {
const classes = [];
function infer(val, fieldName) {
if (val === null) return "Optional[str]";
if (typeof val === "string") return "str";
if (typeof val === "number") return Number.isInteger(val) ? "int" : "float";
if (typeof val === "boolean") return "bool";
if (Array.isArray(val)) {
const first = val.find(v => v !== null);
return first ? `List[${infer(first, fieldName + "Item")}]` : "List[Any]";
}
if (typeof val === "object") {
const clsName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
build(val, clsName);
return clsName;
}
return "Any";
}
function build(obj, cls) {
const fields = Object.entries(obj).map(([k, v]) => ` ${k}: ${infer(v, k)}`);
classes.push(`@dataclass\nclass ${cls}:\n${fields.join("\n")}`);
}
build(obj, name);
return classes.join("\n\n");
}
const data = { id: 1, name: "Alice", scores: [98, 85] };
console.log(jsonToPython(data, "User"));
// @dataclass
// class User:
// id: int
// name: str
// scores: List[int]from pydantic import BaseModel
from typing import List, Optional
class Address(BaseModel):
street: str
city: str
zip: str
class User(BaseModel):
id: int
name: str
email: str
active: bool
score: float
address: Address
tags: List[str]
metadata: Optional[str] = None
# Pydantic parses and validates JSON in one step
raw = '{"id":1,"name":"Alice","email":"alice@example.com","active":true,"score":98.5,"address":{"street":"123 Main St","city":"Springfield","zip":"12345"},"tags":["admin","user"],"metadata":null}'
user = User.model_validate_json(raw)
print(user.name) # -> Alice
print(user.model_dump_json()) # -> re-serializes to JSON# Install the generator
pip install datamodel-code-generator
# Generate dataclasses from a JSON file
datamodel-codegen --input data.json --output models.py --output-model-type dataclasses.dataclass
# Generate Pydantic models instead
datamodel-codegen --input data.json --output models.py
# From a JSON string via stdin
echo '{"id": 1, "name": "Alice", "tags": ["admin"]}' | \
datamodel-codegen --output-model-type dataclasses.dataclass
# Output:
# @dataclass
# class Model:
# id: int
# name: str
# tags: List[str]