JSON’dan Python’a: dataclass, Pydantic ve TypedDict (2026)
JSON’unuzu JSON’dan Python dönüştürücüye yapıştırın ve ürettiği sınıfları kopyalayın. JSON’u Python’a çevirmenin en hızlı yolu bu: kurulacak bir şey yok ve her şey tamamen tarayıcınızda, yerel olarak çalışır. Tek seferlik bir model ya da tanımadığınız bir API yanıtına hızlı bir bakış için işiniz saniyeler içinde biter.
Asıl zor kısım, bir dönüştürücünün sizin yerinize çözemeyeceği şeydir. Doğru tipleri çıkarabilir ama en çok önem taşıyan kararı veremez: üç çıktıdan hangisini gerçekten istediğinizi. Bir dataclass, bir Pydantic v2 BaseModel ve bir TypedDict tıpatıp aynı JSON’u tanımlayabilir; yine de tip güvenliği gücü, çalışma zamanı davranışı ve verinizi içlerine nasıl yüklediğiniz bakımından farklıdırlar. Yanlış seçerseniz ya Pydantic’in bağımlılığını boşuna sırtlanırsınız ya da bir dataclass’ın girdinizi doğruladığını sanırsınız; oysa dataclass bunu sessizce atlar.
Bu rehber; üçü için de karar matrisini, dönüştürücünün tipleri nasıl çıkardığını, her modda camelCase işlenişini, ürettiğiniz sınıfla JSON’u nasıl ayrıştıracağınızı (insanları yakalayan iç içe tuzağı da dahil), Pydantic v2 ile v1 farkını ve çıktıya güvenmeden önce bilmeye değer sınır durumlarını kapsar.
JSON’u Python’a nasıl dönüştürürsünüz
JSON’u Python’a dönüştürmek üç adımdan oluşur:
- JSON’unuzu yapıştırın. Bir nesneyi, diziyi ya da ham API yanıtını giriş kutusuna bırakın. Dönüştürme anında ve tamamen istemci tarafında çalışır.
- dataclass, Pydantic ya da TypedDict seçin. Stilleri değiştirmek için Output düğmesini kullanın ve varsayılan
RootadınıUserya daApiResponsegibi anlamlı bir şeyle değiştirin. - Kopyalayın veya indirin. Üretilen Python’u tek tıkla alın ve
models.pydosyasını doğrudan projenize bırakın.
İşlemsel yolun tamamı bu kadar. Girdiniz küçültülmüşse ya da geçerli olduğundan emin değilseniz, dönüştürücünün okuyacağı temiz ve düzgün biçimli bir JSON elde etmek için önce onu bir JSON biçimlendiriciden geçirin. Rehberin geri kalanı, bir aracın kendi başına çıkaramayacağı durumları düzeltebilmeniz için çıktıyı açıklar.
JSON tipleri Python’a nasıl eşlenir
Her JSON değerinin bir Python karşılığı vardır ve bu eşleme çoğunlukla dolaysızdır:
| JSON değeri | Python tipi |
|---|---|
"text" | str |
42 | int (keyfi hassasiyet, taşma yok) |
3.14, 2e3 | float |
true / false | bool |
null | Optional[T] / Optional[Any] |
[1, 2, 3] | List[T] |
{ ... } | adlandırılmış bir sınıf |
Tipik bir REST payload’ı şöyle görünür:
{ "id": 101, "name": "Ada Lovelace", "email": "ada@example.com", "active": true, "roles": ["admin", "user"] }
dataclass modunda dönüştürücü, kullanıma hazır bir sınıf üretir:
from dataclasses import dataclass
from typing import List
@dataclass
class Root:
id: int
name: str
email: str
active: bool
roles: List[str]
Küçük bir ayrıntı burada fark yaratır: Python’un int tipi keyfi hassasiyetlidir; dolayısıyla bir Discord snowflake’i ya da 2^53’ü aşan herhangi bir ID, hiçbir kayıp olmadan düz bir int olarak kalır. JavaScript aynı değerde hassasiyet kaybederdi, Rust ise sizi i64, u64 ve f64 arasında seçim yapmaya zorlardı. Yalnızca ondalık noktalı ya da üslü yazılmış bir token float olarak çıkarılır. Yalnızca null olarak görünen bir alan tek başına örnekten tiplenemeyeceğinden Optional[Any]’ye geri düşer; Any’den daha keskin bir sonuç almak için değeri doldurulmuş, temsili bir payload yapıştırın.
dataclass, Pydantic v2 ve TypedDict: hangisini kullanmalısınız?
Dönüştürücünün size bıraktığı seçim budur ve bu rehberin de asıl konusu. Kısacası: sıfır bağımlılıklı, dahili bir veri tutucu istediğinizde bir dataclass’a; güvenilmeyen girdiyi ayrıştırdığınızda ya da doğruladığınızda Pydantic v2’ye; zaten elinizdeki dict’ler üzerinde yalnızca statik tip ipuçları istediğinizde ise TypedDict’e uzanın.
| Boyut | dataclass | Pydantic v2 | TypedDict |
|---|---|---|---|
| Bağımlılık | Standart kütüphane | pip install pydantic | Standart kütüphane (typing) |
| Çalışma zamanı doğrulaması | Hayır | Evet, doğrular ve tipe zorlar | Hayır, yalnızca ipucu |
| Çalışma zamanı maliyeti | Hafif (gerçek nesne) | Biraz (doğrulama) | Sıfır (bir dict’tir) |
| İç içe otomatik ayrıştırma | Hayır, elle | Evet, model_validate özyineler | Hayır, bir dict’tir |
| camelCase alias | Orijinal anahtarı korur | Field(alias=...) | İşlevsel sözdizimi |
| En uygun olduğu yer | Dahili yapılar | API yanıtları, webhook’lar, yapılandırma | Eski dict kodunu tipleme |
{"id": 101, "name": "Ada Lovelace", "active": true} gibi küçük bir şekil için üç hedef neredeyse birbirinin aynıdır. JSON’dan Python dataclass’a dönüşüm size standart kütüphaneye ait bir nesne verir:
from dataclasses import dataclass
@dataclass
class Root:
id: int
name: str
active: bool
JSON’dan Pydantic’e giden sürüm BaseModel’i devreye sokar; benzer görünür ama çalışma zamanında hakkını verir:
from pydantic import BaseModel
class Root(BaseModel):
id: int
name: str
active: bool
JSON’dan bir python TypedDict ise yeni bir şey ayırmadan düz bir dict’in şeklini tanımlar:
from typing import TypedDict
class Root(TypedDict):
id: int
name: str
active: bool
Aynı alanlar, birbirinden çok farklı üç sözleşme. Üçünü de tek bir örnekten üretmenin değeri şudur: araçta aralarında geçiş yapıp modu işe göre eşleyebilirsiniz. Kontrol etmediğiniz veriyi ayrıştırırken Pydantic, veri dahiliyken dataclass, hâlihazırda etrafta dolaştırdığınız bir dict’i yalnızca mypy’nin anlamasını istediğinizde ise TypedDict.
Dönüştürücü sınıfları nasıl çıkarır
Üç kural, ona verdiğiniz neredeyse her şeyi kapsar: her nesne şekli için bir sınıf, diziler için anahtar anahtar birleştirme ve eksik değerlerin dikkatli işlenmesi.
Yapısal çıkarım: her nesne için adlandırılmış bir sınıf
Her farklı nesne şekli kendi adlandırılmış sınıfına dönüşür. İç içe nesneler satır içine alınmaz; ayrı, başvurulan tanımlara yükseltilir:
{ "repo": "pydantic", "owner": { "login": "samuelcolvin", "id": 100 } }
from dataclasses import dataclass
@dataclass
class Owner:
login: str
id: int
@dataclass
class Root:
repo: str
owner: Owner
İç içe geçmiş owner, alan üzerinden başvurulan kendi Owner sınıfına dönüşür. Sıraya dikkat edin: alt sınıf, onu kullanan üst sınıftan önce üretilir; böylece modül from __future__ import annotations olmadan çalışır. Aynı şekiller de tekilleştirilir; dolayısıyla aynı yapıdaki iki alan, kopya üretmek yerine tek bir sınıfı paylaşır.
Dizi birleştirme ve Optional alanlar
Bir nesne dizisi geçtiğinizde, dönüştürücü onları anahtar anahtar tek bir eleman tipinde birleştirir. Bazı elemanlarda bulunup diğerlerinde eksik olan bir anahtar Optional hâline gelir:
{ "users": [{ "id": 1, "nick": "x" }, { "id": 2 }] }
from typing import List, Optional, TypedDict
class User(TypedDict):
id: int
nick: Optional[str]
class Root(TypedDict):
users: List[User]
id her elemanda görünür, dolayısıyla zorunlu kalır. nick ikinci kullanıcıda yoktur, bu yüzden Optional[str] olur. Tek bir nesnenin neden zayıf bir örnek olduğu tam olarak budur: araç, bir alanı yalnızca anahtarın bir yerde gerçekten eksik olduğunu gördüğünde Optional olarak işaretleyebilir. Temsili bir dizi verin ki çıkarım gerçek şekli yansıtsın.
Optional, None ve boş diziler
Birkaç değer kendi başına hiçbir tip taşımaz ve dönüştürücü bu konuda dürüsttür. Bazı dizi öğelerinde eksik olan bir anahtar Optional[T] olur. Yalnızca null olarak görünen bir alan Optional[Any] olur; çünkü JSON’daki null tek başına amaçlanan tip hakkında size hiçbir şey söylemez. Boş bir dizi ya da karışık eleman tipleri içeren bir dizi List[Any]’ye geri düşer. Bunların hiçbiri hata değildir; araç yalnızca tahmin yürütmeyi reddeder. Somut bir tip gösteren bir örneğiniz olduğunda her Any’yi onunla değiştirin. Python’un keyfi hassasiyetli int’i de büyük bir ID’yi, Rust ya da JavaScript’te olacağının aksine, daha geniş bir sayısal tipe asla zorlamaz.
Her modda camelCase anahtarları işleme
JSON anahtarları çoğu zaman camelCase iken deyimsel Python alanları snake_case’tir. Burada tek bir doğru yanıt yok; bu yüzden her mod bunu farklı şekilde çözer ve çıktıyı kopyalamadan önce bu farkı anlamaya değer.
dataclass. Bir dataclass’ın yerleşik bir alias mekanizması yoktur. Root(**data)’yı çalışır tutmak için dönüştürücü, geçerli bir Python tanımlayıcısı olduğu sürece orijinal anahtarı alan adı olarak korur; yani publicRepos, publicRepos olarak kalır. Onu snake_case’e zorlamak **data’yı bir TypeError ile bozardı.
Pydantic v2. Burada deyimsel sonucu alırsınız. Alanlar snake_case’e yeniden adlandırılır; bir Field(alias=...) onları tam JSON anahtarına geri eşler ve ayrıca model_config = ConfigDict(populate_by_name=True) sayesinde modeli alan adıyla ya da alias ile kurabilirsiniz:
from pydantic import BaseModel, ConfigDict, Field
class Root(BaseModel):
model_config = ConfigDict(populate_by_name=True)
login: str
public_repos: int = Field(alias="publicRepos")
created_at: str = Field(alias="createdAt")
Böylece kodunuz doğal biçimde okunur, Root.model_validate(api_json) yine de gerçek camelCase payload’larını round-trip eder.
TypedDict. Düz tanımlayıcı anahtarlar doğrudan kullanılır. Tanımlayıcı olmayan bir anahtar belirir belirmez, dönüştürücü tam anahtarı korumak için işlevsel TypedDict('User', {...}) sözdizimine geçer; bunu bir sonraki bölüm ele alır.
Python anahtar sözcükleri ve tanımlayıcı olmayan anahtarlar
JSON anahtarları yalnızca karakter dizileridir; dolayısıyla bir API’nin class, from ya da first-name göndermesini hiçbir şey engellemez. Bunların her biri çıplak bir Python özniteliği olarak sözdizimi hatası olurdu; bu yüzden dönüştürücü onları temizler.
Python anahtar sözcüğü olan bir anahtar, sonuna alt çizgi alır: class, class_ olur; from, from_ olur. Pydantic modunda ayrıca bir Field(alias=...) tutar; böylece model yine de orijinal wire anahtarını okur:
from pydantic import BaseModel, ConfigDict, Field
class Root(BaseModel):
model_config = ConfigDict(populate_by_name=True)
class_: str = Field(alias="class")
from_: str = Field(alias="from")
Tire, boşluk ya da başta rakam içeren anahtarlar, dataclass ve Pydantic modlarında geçerli tanımlayıcılara temizlenir. TypedDict, harfi harfine anahtarı koruyabilen tek moddur; işlevsel biçimi kullanır, böylece "first-name" olduğu gibi hayatta kalır:
from typing import TypedDict
Root = TypedDict("Root", {"first-name": str, "2fa": bool})
Sonuç her zaman çalışır ve TypedDict modunda anahtar, API’nin gönderdiği şeyin bayt bayt aynısı olarak kalır.
Üretilen sınıfla JSON’u ayrıştırma
Sınıfı üretmek işin yarısıdır. JSON’u ona yüklemek ise üç modun keskin biçimde ayrıştığı ve yaygın bir varsayımın yanlışa düştüğü yerdir.
dataclass. Düz bir nesne için json.loads artı Root(**data) doğrudan çalışır:
import json
from dataclasses import dataclass
from typing import List
@dataclass
class Root:
id: int
name: str
roles: List[str]
data = json.loads('{"id": 101, "name": "Ada Lovelace", "roles": ["admin"]}')
root = Root(**data)
print(root.name, root.roles)
Ama bir dataclass özyinelemez. JSON’da iç içe nesneler varsa, Root(**data) üst düzeyi doldurur ve her alt öğeyi ürettiğiniz Owner sınıfı olarak değil düz bir dict olarak bırakır. Bütün bir ağacı ayrıştırmak için ya alt öğeleri kendiniz kurun, ya dacite gibi bir kütüphane ya da pydantic.dataclasses kullanın, ya da aracı Pydantic moduna geçirin. Çoğu dönüştürücünün asla söz etmediği tuzak budur.
Pydantic v2. Tek bir çağrı, ağacın tamamını ayrıştırır ve doğrular:
import json
from pydantic import BaseModel
class Root(BaseModel):
id: int
name: str
root = Root.model_validate(json.loads('{"id": 101, "name": "Ada Lovelace"}'))
print(root.name)
Bir tip uyuşmazlığı, sessizce geçmek yerine açık bir ValidationError fırlatır. Bağımlılığın karşılığı budur: model bir çalışma zamanı doğrulayıcısıdır; dolayısıyla geri dönen bir model_validate çağrısı, verinin gerçekten eşleştiğine dair bir garantidir, bir tip denetleyicisinin sunduğu türden salt bir inanç değil.
TypedDict. Çalışma zamanında bir TypedDict, sıradan bir dict’tir. data: Root = json.loads(text) biçiminde açıklama eklemek tamamen statik denetleyici içindir; kod çalışırken hiçbir şey doğrulanmaz. Gerçek bir zorlamaya ihtiyacınız varsa mypy’yi CI’da çalıştırın ya da Pydantic’e geçin. Bir mod seçmek, ne kadar çalışma zamanı garantisi istediğinizi seçmektir; bir sözleşmenin tiplerin ötesine geçmesi gerektiğindeyse JSON Schema doğrulama rehberi yapıyı baştan sona zorlamayı ele alır.
Pydantic v2 ile v1 — ne değişti
Dönüştürücü v2 sözdizimi üretir. Pek çok kod tabanı hâlâ v1 kullanıyor ve v2 çıktısını bir v1 projesine yapıştırmak, mantık yüzünden değil yeniden adlandırılmış metotlar yüzünden başarısız olur. Eşleme şöyle:
| Görev | Pydantic v2 (araç çıktısı) | Pydantic v1 |
|---|---|---|
| Bir dict ayrıştır | model_validate(data) | parse_obj(data) |
| Ham JSON ayrıştır | model_validate_json(text) | parse_raw(text) |
| Modeli yapılandır | model_config = ConfigDict(...) | iç class Config |
| dict’e serileştir | model_dump() | dict() |
| JSON’a serileştir | model_dump_json() | json() |
Alias davranışı da sıkılaştı: v2’de bir modeli hem alan adı hem de alias ile kurabilmek için Field(alias=...) ile birlikte populate_by_name=True gerekir; aracın bunu eklemesinin nedeni de budur. Pratik kural kısadır. Yapabiliyorsanız v2’ye yükseltin, çünkü daha hızlıdır ve güncel geliştirmenin hedefidir; aksi hâlde model_validate’i parse_obj’a ve ConfigDict’i iç bir Config’e geri yazın.
json-to-python, quicktype, datamodel-code-generator ve elle yazma
JSON’dan bir Python sınıfı üretmenin tek bir en iyi yolu yoktur. Bu, JSON’un nerede yaşadığına ve başlangıçta neyiniz olduğuna bağlıdır.
| Yaklaşım | En uygun olduğu yer | Not |
|---|---|---|
| Çevrimiçi dönüştürücü (bu araç, jsonlint, codeshack) | Tek seferlik dönüşümler, hassas payload’lar, sıfır kurulum | Bir örnekten çıkarım yapar, tamamen istemci tarafında |
| quicktype | Çok dilli çıktı, pipeline kod üretimi | O da örnek tabanlı; Python desteği alias ve mod seçiminde daha zayıf |
| datamodel-code-generator | Bir JSON Schema’sından ya da OpenAPI’den Pydantic üretme | Girdi bir örnek değil, bir şemadır; elinizde bir tane olduğunda daha yetkilidir |
| Sınıfları elle yazma | Küçücük payload’lar, sözdizimini öğrenme | Tam kontrol ama zahmetli ve kayması kolay |
Aradaki temel ayrım şu: çevrimiçi bir dönüştürücü ile quicktype, tiplerini JSON’un bir örneğinden çıkarır; datamodel-code-generator ise bir JSON Schema ya da OpenAPI belirtimini gerçeğin kaynağı olarak okur. Örnek tabanlı araçları keşif ve tek seferlik işler için kullanın; bir sözleşme zaten varsa şema tabanlı olana uzanın. Kod tabanınız Python yerine TypeScript ise aynı örnek tabanlı yaklaşım JSON’dan TypeScript’e dönüştürücü ile geçerlidir ve JSON’dan TypeScript interface rehberi o tarafı derinlemesine ele alır. Güçlü tipli, derlenen bir dilde çalışma zamanı doğrulaması açısı için JSON’dan Rust struct rehberi yararlı bir karşıtlık sunar: serde, Rust’ın Pydantic’idir.
JSON’dan Python üretirken sık karşılaşılan tuzaklar
Üretilen sınıflar bir başlangıç noktasıdır. Çıktıya canlı veriyle güvenmeden önce şunlara dikkat edin.
- Tek bir örnek nadiren her şekli ortaya çıkarır.
Optional, yalnızca gerçekten farklılaşan dizi elemanlarından çıkarılabilir. İsteğe bağlılığın, tek şanslı bir nesneden çıkarılan bir tahmin değil de doğru olması için temsili bir dizi yapıştırın. - Bir dataclass doğrulama yapmaz.
Root(**data)yalnızca alanları atar; hiçbir tipi denetlemez ve hiçbir şeye özyinelemez. Zorlamaya ihtiyacınız varsa Pydantic kullanın. - İç içe JSON
Root(**data)’yı bozar. Yalnızca üst düzey doldurulur; alt öğeler dict olarak kalır. Pydantic’inmodel_validate’ine geçin ya da dacite kullanın. - Her zaman
nullolan bir alanOptional[Any]olur. Bunu normal bir isteğe bağlı alan değil, bir yer tutucu olarak görün ve bir tip öğrendiğinizde ona gerçek bir tip verin. - v1 projesinde v2 çıktısı.
model_validatetanımsız olacaktır. v2’ye yükseltin ya da onuparse_objolarak yeniden yazın. strolarak bırakılan bir tarih, tarih hesabı yapamaz. Alanıdatetime’a çevirin ya da Pydantic’te birdatetimealanı kullanın; böylece ISO 8601’i sizin için ayrıştırır.
Sıkça sorulan sorular
JSON için dataclass, Pydantic mi yoksa TypedDict mi kullanmalıyım?
Sıfır bağımlılıklı, dahili bir veri tutucu için bir dataclass kullanın. Güvenilmeyen girdiyi ayrıştırırken ya da doğrularken Pydantic v2 kullanın, çünkü tipleri çalışma zamanında zorlar. Zaten elinizde olan bir dict’e çalışma zamanı maliyeti olmadan statik ipuçları eklemek için TypedDict kullanın. Veri, kontrolünüzün dışından geldiğinde varsayılan olarak Pydantic’i seçin.
Pydantic JSON’u çalışma zamanında doğrular mı?
Evet. Root.model_validate(data) kod çalışırken tipleri doğrular ve zorlar; hatalı girdide bir ValidationError fırlatır. Bir dataclass bunların ikisini de yapmaz; Root(**data) yalnızca alanları atar. Bir TypedDict de ikisini yapmaz; mypy gibi statik denetleyiciler için bir ipucudur ve çalışma zamanında düz bir dict gibi davranır.
JSON’un bazen atladığı bir alanı nasıl tiplerim?
Onu Optional[T] olarak tipleyin. Bir anahtar yalnızca bazı dizi elemanlarında göründüğünde, dönüştürücü onu otomatik olarak Optional işaretler. Pydantic’te alana = None gibi bir varsayılan verin; böylece eksik bir anahtar doğrulama hatasını tetiklemez. Bir dataclass alanı da aynı şekilde field(default=None) ile varsayılan alabilir.
dataclass’ım neden iç içe JSON’u ayrıştıramadı?
Çünkü Root(**data) özyinelemez. Üst düzey alanları doldurur ve iç içe nesneleri, ürettiğiniz alt sınıflar yerine düz dict olarak bırakır. Bütün ağacı tek çağrıda ayrıştırmak için Pydantic’in model_validate’ine geçin ya da dacite veya pydantic.dataclasses ile özyineleme ekleyin.
Büyük bir JSON tam sayısı hangi Python tipine dönüşür?
int. Python tam sayıları keyfi hassasiyetlidir; bu yüzden bir snowflake ya da 2^53’ü aşan bir Discord ID hiçbir kayıp olmadan düz bir int olarak kalır. JavaScript’teki hassasiyet kaybına asla çarpmaz ve Rust’ın sizi zorladığı gibi i64 ile u64 arasında asla seçim yapmak zorunda kalmazsınız.
camelCase JSON anahtarları her modda nasıl işlenir?
Bir dataclass orijinal anahtarı korur; böylece Root(**data) yine çalışır. Pydantic, alanları Field(alias="camelKey") artı populate_by_name=True ile snake_case’e yeniden adlandırır; böylece gerçek API verisini round-trip eder. TypedDict, geçerli bir tanımlayıcı olmayan herhangi bir anahtarı korumak için işlevsel TypedDict('Name', {...}) sözdizimini kullanır.
class gibi bir Python anahtar sözcüğü olan JSON anahtarını nasıl ele alırım?
Dönüştürücü sonuna bir alt çizgi ekler ve class’ı class_’a çevirir; böylece kod geçerli olur. Pydantic modunda ayrıca Field(alias="class") ekleyerek alanı orijinal wire anahtarına geri eşler; böylece ad yasaldır ve model yine de gerçek payload’ı okur.
Çevrimiçi bir JSON’dan Python dönüştürücü kullanırken JSON’um gizli kalır mı?
Evet. Dönüştürme %100 tarayıcınızda JavaScript ile çalışır. JSON’unuz (token’lar, ID’ler ve müşteri verileri dahil) sayfadan asla ayrılmaz ve hiçbir sunucuya gitmez. Sayfa yüklendikten sonra çevrimdışı bile çalışır. Hazır olduğunuzda kendi payload’ınızda JSON’dan Python dönüştürücüyü deneyin.