İçeriğe geç

Menü

Berk Akademi
Yorumlar Google yorumları Özel Ders Başvuru Ücretsiz ön görüşme Ana Sayfa

Python TypeError: Object of type set is not JSON serializable Çözümü

python-typeerror-object-of-type-set-is-not-json-serializable
Bu yazıda neler var?
  1. Bu hata neden çıkıyor? Önce hatayı üretelim
  2. En kısa çözüm: seti list() ile listeye çevir
  3. Veri iç içeyse: json.dumps() içinde default fonksiyonu
  4. Hangi yolu seçmeli: list, sorted, default ve str karşılaştırması
  5. Okunabilir çıktı için indent ve ensure_ascii=False

Python'da json.dumps() bir set gördüğünde "TypeError: Object of type set is not JSON serializable" hatası verir. Çözüm, seti JSON'un tanıdığı bir tipe çevirmektir; çoğu durumda list(...) yeterli olur. JSON, Python'daki her veri tipini doğrudan taşımaz; önce JSON'un desteklediği bir tipe dönüştürmelisin. Veri iç içeyse default parametresiyle bu dönüşümü tek yerde tanımlayabilirsin.

Bu hata neden çıkıyor? Önce hatayı üretelim

Set içeren küçük bir sözlüğü JSON metnine çevirmeyi deneyelim:

import json

veri = {"kullanici": "Ali", "etiketler": {"python", "json", "python"}}
print(veri)
print(json.dumps(veri))

İlk print satırı sözlüğü yazdırır. Etiketlerin sırası çalıştırmadan çalıştırmaya değişebilir, ama "python" tek kez görünür:

{'kullanici': 'Ali', 'etiketler': {'python', 'json'}}

İkinci satırda hata oluşur. Traceback'in son satırı şöyledir:

TypeError: Object of type set is not JSON serializable

Mesaj, json modülünün set nesnesini JSON'a nasıl yazacağını bilmediğini söyler.

Set ve liste arasındaki fark

Set süslü parantezle yazılır ve her değeri yalnızca bir kez tutar. Örnekte "python" iki kez yazıldı, ama sette tek kopyası kalır. Liste ise köşeli parantezle yazılır, tekrarlı değerleri korur ve elemanlarını bir sıra içinde tutar. Resmî Python dokümantasyonu seti, benzersiz ve karma (hashable) nesnelerden oluşan sırasız bir koleksiyon olarak tanımlar.

JSON'un tip kümesi ise sınırlıdır: nesne, dizi, metin, sayı, true/false ve null. Python'un json modülü dokümantasyonundaki eşleme tablosuna göre dict nesneye, list ve tuple diziye, str metne, int ve float sayıya, True/False mantıksal değerlere, None da null'a dönüşür. Tabloda set yoktur; JSON'da setin doğrudan bir karşılığı olmadığı için modül hata verir.

Küçük bir sınır notu: tuple JSON'a dizi olarak yazılabilir, frozenset ise tıpkı set gibi aynı hatayı verir.

En kısa çözüm: seti list() ile listeye çevir

En kısa çözüm: seti list() ile listeye çevir

Hatayı gideren en kısa yol, seti JSON'un tanıdığı bir tipe, yani listeye çevirmektir:

import json

veri = {"kullanici": "Ali", "etiketler": {"python", "json", "python"}}
veri["etiketler"] = list(veri["etiketler"])

print(json.dumps(veri))

Beklenen çıktı şuna benzer olur:

{"kullanici": "Ali", "etiketler": ["python", "json"]}

Burada list() setin elemanlarını yeni bir listeye kopyalar ve json.dumps() o listeyi JSON dizisi olarak yazar. Orijinal sözlükteki set değişir, o yüzden gerekiyorsa önce sözlüğün bir kopyasını al.

Dikkat edilecek nokta sıradır. Set sırasız bir koleksiyondur; list() sonucundaki sıranın her çalıştırmada aynı olacağına güvenme. Çıktının her seferinde aynı sırada olması gerekiyorsa bu bölümdeki basit dönüşüm yetmez, sıra için ayrı bir karar vermek gerekir.

Set, liste ve sözlük arasındaki bu ayrımı kendi başına yoklamak istersen ücretsiz Python bilgi testi veri yapılarındaki seviyeni görmek için iyi bir başlangıç noktasıdır.

Veri iç içeyse: json.dumps() içinde default fonksiyonu

Veri iç içeyse: json.dumps() içinde default fonksiyonu

Set; sözlüklerin ve listelerin derinlerinde olduğunda her yeri tek tek list() ile dönüştürmek zahmetlidir. Bunun yerine json.dumps() çağrısına bir default fonksiyonu verebilirsin. Resmî dokümantasyona göre default, json modülünün kendiliğinden serileştiremediği nesneler için çağrılır; JSON'a çevrilebilir bir değer döndürmeli ya da TypeError fırlatmalıdır.

import json

def donustur(nesne):
    if isinstance(nesne, set):
        return list(nesne)
    raise TypeError(f"{type(nesne).__name__} türü JSON'a çevrilemiyor")

veri = {
    "ad": "Ece",
    "etiketler": {"python"},
    "projeler": [{"ad": "Not", "konular": {"json"}}]
}

print(json.dumps(veri, default=donustur))

Beklenen çıktı:

{"ad": "Ece", "etiketler": ["python"], "projeler": [{"ad": "Not", "konular": ["json"]}]}

Fonksiyon yalnızca sorunlu nesnelerde devreye girer. Metin, sayı, liste ve sözlük gibi değerleri json modülü kendisi yazar; donustur bunlar için çağrılmaz. Set ne kadar derinde olursa olsun, json.dumps() ona rastladığında fonksiyonu çağırır.

Bilmediğin tipte hatayı yeniden fırlat

Fonksiyonun son satırındaki raise TypeError(...) önemlidir. Bu satırı silersen fonksiyon tanımadığı nesne için None döndürür ve çıktıda bu değer null olarak görünür. Hata fark edilmeden kaybolur, bozuk veri JSON'a yazılır. Örneğin 1+2j gibi bir karmaşık sayı yukarıdaki fonksiyona gelirse şu mesajla durursun:

complex türü JSON'a çevrilemiyor

Hatayı görmek, sessizce yanlış veri üretmekten her zaman daha güvenlidir.

Hangi yolu seçmeli: list, sorted, default ve str karşılaştırması

Üç çözümün de işe yaradığı durumlar vardır; fark, verinin yapısında ve çıktıdan ne beklediğinde ortaya çıkar.

YolNe zaman uygunSınırı
list(set)Set tek bir yerde ve sıra önemli değilseEleman sırası garanti edilmez; iç içe yapıda her sete ayrı ayrı uygulanır
sorted(set)Çıktının tekrarlanabilir ya da karşılaştırılabilir olması gerekiyorsaElemanlar birbiriyle karşılaştırılabilir olmalıdır
default fonksiyonuSet birden çok yerde ya da iç içe yapıların derinindeyseSıralama yapmaz; her tip için kural yazman gerekir

str(set) zayıf bir çözümdür. Sonuç JSON dizisi değil, tek bir metindir; karşı taraf bunu eleman eleman okumak yerine metni kendisi ayrıştırmak zorunda kalır.

Sıra için sorted() kullan. Set elemanlarının hangi sırayla geleceğine güvenemezsin. Çıktıyı test, günlük kaydı ya da dosya karşılaştırması için kullanacaksan sorted() aynı veriden her seferinde aynı listeyi üretir.

Karışık tiplerde sorted() hata verir. Sayı ve metin bir arada olduğunda Python bunları kıyaslayamaz:

sorted({1, "a"})
# TypeError: '<' not supported between instances of 'str' and 'int'

Elemanları baştan aynı tipe getirebilir ya da key=str gibi bir anahtar verebilirsin. sorted({1, "a"}, key=str) çağrısı [1, 'a'] döndürür.

frozenset ve tuple için kısa not. frozenset da set gibi kendiliğinden serileştirilemez; default içinde isinstance(nesne, (set, frozenset)) ile ikisini birlikte yakalayabilirsin. Tuple ise sorun çıkarmaz: json.dumps() onu dizi olarak yazar. Ancak JSON'dan geri okuduğunda tuple değil liste elde edersin.

Okunabilir çıktı için indent ve ensure_ascii=False

Resmî json dokümantasyonuna göre indent varsayılan olarak None gelir ve bu durumda en sıkışık gösterim seçilir. Yani çıktı tek satırda akar. indent=2 gibi bir değer verirsen dizi elemanları ve nesne üyeleri o girinti düzeyiyle alt alta yazılır. ensure_ascii ise varsayılan olarak True'dur. Bu durumda ASCII dışındaki her karakter kaçış dizisine çevrilir: ş harfi u015f, ğ harfi u011f, ı harfi u0131 olur. Çıktı geçerli JSON kalır ama gözle okunmaz.

import json

def donustur(nesne):
    if isinstance(nesne, set):
        return sorted(nesne)
    raise TypeError(f"{type(nesne).__name__} tipi JSON'a çevrilemiyor")

veri = {"şehir": "İzmir", "ilgi": {"yazılım", "oyun"}}

print(json.dumps(veri, default=donustur, indent=2, ensure_ascii=False))

Beklenen çıktı:

{
  "şehir": "İzmir",
  "ilgi": [
    "oyun",
    "yazılım"
  ]
}

Setin elemanlarının sırası güvenceye bağlı olmadığı için default fonksiyonunda sorted() kullandık. Böylece çıktı her çalıştırmada aynı kalır. Çıktıyı dosyaya yazacaksan dosyayı encoding="utf-8" ile açmayı unutma.

Bu hata ve benzerleri, tip dönüşümü ile temel veri yapıları (liste, küme, sözlük) oturduğunda kolayca çözülür. Konuları sırayla ve kendi hızında pekiştirmek istiyorsan kişiye özel müfredatlı birebir Python özel ders programı bu temelleri adım adım kurmanın yollarından biridir.

Özetle: set JSON'a doğrudan girmez. Onu listeye çevirir, iç içe yapılarda default fonksiyonundan yararlanır, çıktıyı da indent ve ensure_ascii=False ile okunur hâle getirirsin.

Bu içerik aradığın cevabı verdi mi?
Yanıtın, hangi yazıları geliştirmemiz gerektiğini anlamamıza yardımcı olur.
Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

Bu konudan sonra ne okuyabilirsin?

Tüm yazılar

İlgili Eğitimler

Berk Keskin, yazılım geliştirici ve eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; İzmir Ekonomi Üniversitesi'ni bölüm birincisi ve yüksek şeref öğrencisi olarak tamamladı. Bugün yalnızca eğitim vermekle kalmıyor, sektörde aktif olarak yazılım projeleri geliştiriyor ve gerçek dünya deneyimini birebir derslerine taşıyor. Ezberden uzak, mühendislik zihniyetini merkeze alan sürdürülebilir öğrenme sistemleri tasarlayarak sorgulayan, üreten ve problem çözebilen yeni nesil yazılımcılar yetiştiriyor.

Sektörel Deneyim & Projeler

  • Ticarify Entegrasyon Yazılım logosu CEO Ticarify Entegrasyon YazılımPazaryerleri ve e-ticaret sitelerine otomatik e-fatura kesimi, sipariş ve kargo takibi hizmetleri sunan e-Dönüşüm platformunun API mimarisini ve yazılım ekibini yönetmektedir.
  • Benim Düğünüm logosu CEO Benim DüğünümDijital etkinlik ve anı paylaşım platformu.
  • Siberdizayn logosu Yazılım Ekibi Lideri SiberdizaynYüksek anlık oyuncu trafiğine sahip oyun kontrol panelleri ve sunucu altyapıları geliştiren yazılım ekibine liderlik etmektedir.
  • MEDYOGRAFYA 360° Dijital Çözümler logosu Dijital Strateji Lideri MEDYOGRAFYA 360° Dijital ÇözümlerŞirketlerin dijital çözümlerde uzun vadede nasıl ilerlemesi gerektiği ve dijital dönüşüm süreçlerinin yönetilmesine destek olmaktadır.
  • İzmir Ekonomi Üniversitesi logosu Danışma Kurulu Üyesi İzmir Ekonomi ÜniversitesiMezun olduğu üniversitesinde, Bilgisayar Programcılığı bölümünün akademik müfredatını güncel sektör ihtiyaçlarına göre şekillendirmek adına Danışma Kurulu'nda görev almaktadır.
WhatsApp Hemen Ara