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

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

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.
| Yol | Ne zaman uygun | Sınırı |
|---|---|---|
list(set) | Set tek bir yerde ve sıra önemli değilse | Eleman 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ı gerekiyorsa | Elemanlar birbiriyle karşılaştırılabilir olmalıdır |
default fonksiyonu | Set birden çok yerde ya da iç içe yapıların derinindeyse | Sı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.