JSON, CSV ve Dosya Formatları
Programlar arası veri alışverişi günümüz yazılım dünyasının temel taşı. Bir API'den gelen JSON veriyi okumak, bir Excel tablosunu CSV olarak işlemek, ayar dosyalarını yönetmek — bunların hepsi bu dersin konusu. Python bu işler için harika araçlar sunuyor.
JSON Nedir?
JSON (JavaScript Object Notation) günümüzde en yaygın veri formatı. Web API'ler, yapılandırma dosyaları, veritabanları — neredeyse her yerde JSON kullanılıyor.
🧳 Bavul Analojisi
JSON'ı bir standart bavul gibi düşün. Farklı ülkelere giderken (farklı programlama dilleri) her seferinde farklı bavul almak zorunda değilsin. JSON, tüm dillerin anlayabildiği evrensel bir paketleme formatı. Python sözlüğünü JSON'a çevirirsin, JavaScript onu açar ve anlar. Java, Go, Ruby — hepsi JSON okuyabilir. Bu yüzden internet dünyasının lingua franca'sı JSON.
JSON Formatı
{
"ad": "Ayşe",
"yas": 25,
"aktif": true,
"hobiler": ["okumak", "yüzmek", "kodlamak"],
"adres": {
"sehir": "İstanbul",
"ilce": "Kadıköy"
},
"telefon": null
}JSON'ın kuralları basit:
Anahtarlar çift tırnak ile yazılır (tek tırnak geçersiz!)
Değerler: string, number, boolean (
true/false), array, object,nullTrailing comma yok (son elemandan sonra virgül konmaz)
Python ile JSON İşlemleri
Python'ın json modülü JSON ile çalışmak için dört temel fonksiyon sunar:
| Fonksiyon | Yön | Kaynak/Hedef |
|---|---|---|
json.dumps() | Python → JSON string | Bellek |
json.loads() | JSON string → Python | Bellek |
json.dump() | Python → JSON dosyası | Dosya |
json.load() | JSON dosyası → Python | Dosya |
Kolay hatırlama: "s" harfi string demek. dumps = dump to string, loads = load from string.
dumps() ve loads() — String İşlemleri
import json
# Python sözlüğü → JSON string
kullanici = {
"ad": "Mehmet",
"yas": 30,
"aktif": True,
"hobiler": ["futbol", "satranç"],
"adres": None
}
json_str = json.dumps(kullanici)
print(json_str)
# {"ad": "Mehmet", "yas": 30, "aktif": true, "hobiler": ["futbol", "satran\u00e7"], "adres": null}
print(type(json_str)) # <class 'str'>Dikkat et: Python'daki True → JSON'da true, None → null oldu. Ve Türkçe karakterler Unicode escape'e dönüştü.
# JSON string → Python sözlüğü
json_verisi = '{"ad": "Ali", "yas": 25, "aktif": false}'
python_dict = json.loads(json_verisi)
print(python_dict) # {'ad': 'Ali', 'yas': 25, 'aktif': False}
print(type(python_dict)) # <class 'dict'>
print(python_dict["ad"]) # AliJSON ↔ Python Veri Tipi Eşleşmesi
| JSON | Python | Ters Yön |
|---|---|---|
object {} | dict | dict → object |
array [] | list | list, tuple → array |
string | str | str → string |
number (int) | int | int → number |
number (float) | float | float → number |
true / false | True / False | True/False → true/false |
null | None | None → null |
⚠️ Dikkat: Python'daki
tupleJSON'a çevrilirkenarray'e dönüşür. Geri okurkenlistolarak gelir — orijinaltuplebilgisi kaybolur. Aynı şekildesetvecomplexgibi türler JSON'da doğrudan desteklenmez.
dump() ve load() — Dosya İşlemleri
import json
# Python → JSON dosyası
kullanicilar = [
{"ad": "Ali", "yas": 25},
{"ad": "Veli", "yas": 30},
{"ad": "Ayşe", "yas": 28}
]
with open("kullanicilar.json", "w", encoding="utf-8") as f:
json.dump(kullanicilar, f)
# JSON dosyası → Python
with open("kullanicilar.json", "r", encoding="utf-8") as f:
yuklenen = json.load(f)
print(yuklenen)
# [{'ad': 'Ali', 'yas': 25}, {'ad': 'Veli', 'yas': 30}, {'ad': 'Ayşe', 'yas': 28}]Pretty Print: Okunabilir JSON
Varsayılan json.dumps() çıktısı tek satır — insan okumak için uygun değil. indent parametresi bunu düzeltir:
import json
veri = {
"proje": "Python Kursu",
"versiyon": "2.0",
"moduller": [
{"ad": "Temel", "ders_sayisi": 10},
{"ad": "İleri", "ders_sayisi": 8}
],
"ayarlar": {
"dil": "tr",
"tema": "koyu"
}
}
# Okunabilir format
guzel_json = json.dumps(veri, indent=4, ensure_ascii=False)
print(guzel_json)Çıktı:
{
"proje": "Python Kursu",
"versiyon": "2.0",
"moduller": [
{
"ad": "Temel",
"ders_sayisi": 10
},
{
"ad": "İleri",
"ders_sayisi": 8
}
],
"ayarlar": {
"dil": "tr",
"tema": "koyu"
}
}Önemli parametreler:
json.dumps(veri,
indent=4, # 4 boşluk girintileme
ensure_ascii=False, # Türkçe karakterleri olduğu gibi yaz
sort_keys=True, # Anahtarları alfabetik sırala
separators=(",", ": ") # Ayırıcıları özelleştir
)
# Dosyaya da aynı parametreler geçerli
with open("cikti.json", "w", encoding="utf-8") as f:
json.dump(veri, f, indent=2, ensure_ascii=False)ensure_ascii=False Türkçe içerik yazarken çok önemli. Bu olmadan "ç", "ş", "ğ" gibi karakterler \u00e7, \u015f, \u011f olarak yazılır.
Custom Serialization: default Parametresi
JSON sadece temel veri tiplerini destekler. datetime, set, Decimal gibi türler JSON'a doğrudan çevrilemez:
import json
from datetime import datetime
veri = {
"tarih": datetime.now(),
"etiketler": {"python", "json", "tutorial"}
}
# Bu hata verir!
# json.dumps(veri) # TypeError: Object of type datetime is not JSON serializabledefault parametresi ile bu sorunu çözersin:
import json
from datetime import datetime, date
from decimal import Decimal
def ozel_serializer(nesne):
"""JSON'ın desteklemediği türleri çevirir."""
if isinstance(nesne, (datetime, date)):
return nesne.isoformat()
if isinstance(nesne, set):
return list(nesne)
if isinstance(nesne, Decimal):
return float(nesne)
if isinstance(nesne, bytes):
return nesne.decode("utf-8")
raise TypeError(f"Serileştirilemeyen tür: {type(nesne).__name__}")
veri = {
"tarih": datetime(2024, 6, 15, 14, 30),
"etiketler": {"python", "json"},
"fiyat": Decimal("29.99")
}
json_str = json.dumps(veri, default=ozel_serializer, indent=2, ensure_ascii=False)
print(json_str)Çıktı:
{
"tarih": "2024-06-15T14:30:00",
"etiketler": ["json", "python"],
"fiyat": 29.99
}JSONEncoder Alt Sınıfı
Daha düzenli bir yaklaşım:
import json
from datetime import datetime
class OzelEncoder(json.JSONEncoder):
def default(self, nesne):
if isinstance(nesne, datetime):
return nesne.isoformat()
if isinstance(nesne, set):
return sorted(list(nesne))
return super().default(nesne)
veri = {"zaman": datetime.now(), "renkler": {"kırmızı", "mavi"}}
print(json.dumps(veri, cls=OzelEncoder, ensure_ascii=False, indent=2))CSV İşlemleri
CSV (Comma-Separated Values) tablo verileri için en basit format. Excel, Google Sheets, veritabanları — hepsi CSV destekler.
ad,yas,sehir
Ali,25,İstanbul
Veli,30,Ankara
Ayşe,28,İzmircsv.reader() — Satır Satır Okuma
import csv
with open("ogrenciler.csv", "r", encoding="utf-8") as f:
okuyucu = csv.reader(f)
# İlk satır başlıklar
basliklar = next(okuyucu)
print(f"Sütunlar: {basliklar}")
# Geri kalan satırlar veri
for satir in okuyucu:
ad, yas, sehir = satir
print(f"{ad} ({yas}) - {sehir}")csv.writer() — Yazma
import csv
ogrenciler = [
["Ad", "Yaş", "Şehir"],
["Ali", 25, "İstanbul"],
["Veli", 30, "Ankara"],
["Ayşe", 28, "İzmir"],
]
with open("cikti.csv", "w", encoding="utf-8", newline="") as f:
yazici = csv.writer(f)
yazici.writerows(ogrenciler) # Tüm satırları yaz
# veya tek tek:
# yazici.writerow(["Fatma", 22, "Bursa"])newline="" parametresi önemli — Windows'ta çift satır sonu sorunu oluşmaması için gerekli.
csv.DictReader() — Sözlük Olarak Okuma
import csv
with open("ogrenciler.csv", "r", encoding="utf-8") as f:
okuyucu = csv.DictReader(f)
for satir in okuyucu:
print(f"Ad: {satir['Ad']}, Yaş: {satir['Yaş']}, Şehir: {satir['Şehir']}")DictReader ilk satırı otomatik olarak başlık kabul eder ve her satırı sözlük olarak döndürür. Sütun ismiyle erişmek indeksle erişmekten çok daha okunabilir.
csv.DictWriter() — Sözlük Olarak Yazma
import csv
ogrenciler = [
{"ad": "Ali", "yas": 25, "sehir": "İstanbul"},
{"ad": "Veli", "yas": 30, "sehir": "Ankara"},
{"ad": "Ayşe", "yas": 28, "sehir": "İzmir"},
]
with open("cikti.csv", "w", encoding="utf-8", newline="") as f:
alan_adlari = ["ad", "yas", "sehir"]
yazici = csv.DictWriter(f, fieldnames=alan_adlari)
yazici.writeheader() # Başlık satırını yaz
yazici.writerows(ogrenciler) # Tüm verileri yazCSV Dialect ve Delimiter
Her CSV dosyası virgül kullanmaz — bazıları noktalı virgül, tab veya başka ayırıcılar kullanır:
import csv
# Noktalı virgül ayırıcılı (Avrupa formatı)
with open("avrupa_veri.csv", "r", encoding="utf-8") as f:
okuyucu = csv.reader(f, delimiter=";")
for satir in okuyucu:
print(satir)
# Tab ayırıcılı (TSV)
with open("veri.tsv", "r", encoding="utf-8") as f:
okuyucu = csv.reader(f, delimiter="\t")
for satir in okuyucu:
print(satir)Özel dialect tanımlama:
import csv
# Özel dialect kaydet
csv.register_dialect("turkce",
delimiter=";",
quotechar='"',
quoting=csv.QUOTE_MINIMAL,
lineterminator="\n"
)
with open("veri.csv", "w", encoding="utf-8", newline="") as f:
yazici = csv.writer(f, dialect="turkce")
yazici.writerow(["Ad", "Soyad", "Not"])
yazici.writerow(["Ali", "Yılmaz", "85"])CSV Sniffer ile Format Algılama
Dosyanın formatını bilmiyorsan Sniffer yardımcı olabilir:
import csv
with open("bilinmeyen.csv", "r") as f:
ornek = f.read(1024)
dialect = csv.Sniffer().sniff(ornek)
print(f"Ayırıcı: '{dialect.delimiter}'")
f.seek(0)
okuyucu = csv.reader(f, dialect)
for satir in okuyucu:
print(satir)configparser: INI Dosyaları
Basit yapılandırma dosyaları için INI formatı hâlâ yaygın:
; config.ini
[genel]
uygulama_adi = Python Kursu
versiyon = 2.0
debug = false
[veritabani]
host = localhost
port = 5432
ad = egitim_db
kullanici = admin
[email]
smtp_sunucu = smtp.gmail.com
port = 587import configparser
# Okuma
config = configparser.ConfigParser()
config.read("config.ini", encoding="utf-8")
# Değerlere erişim
print(config["genel"]["uygulama_adi"]) # Python Kursu
print(config["veritabani"]["host"]) # localhost
print(config.getint("veritabani", "port")) # 5432 (int olarak)
print(config.getboolean("genel", "debug")) # False (bool olarak)
# Varsayılan değer
print(config.get("genel", "tema", fallback="açık")) # "açık"
# Tüm bölümleri listele
print(config.sections()) # ['genel', 'veritabani', 'email']import configparser
# Yazma
config = configparser.ConfigParser()
config["genel"] = {
"uygulama_adi": "Yeni Uygulama",
"versiyon": "1.0"
}
config["veritabani"] = {
"host": "localhost",
"port": "3306"
}
with open("yeni_config.ini", "w", encoding="utf-8") as f:
config.write(f)INI formatı basit key-value ayarlar için ideal. Ama iç içe yapılar veya listeler gerekiyorsa JSON veya YAML tercih et.
pickle: Python Nesne Serialization
pickle modülü herhangi bir Python nesnesini binary formata çevirir ve geri okur. JSON'dan farkı: Python'a özgüdür ama her Python nesnesini serileştirebilir.
import pickle
# Karmaşık Python nesnesi
veri = {
"kullanicilar": [
{"ad": "Ali", "puanlar": {90, 85, 95}}, # set
{"ad": "Veli", "puanlar": {70, 80, 75}}
],
"toplam": 6,
"hesaplanma": lambda x: x * 2 # Dikkat: lambda serialize edilemez!
}
# NOT: lambda ve fonksiyonlar pickle ile sorunlu olabilir
# Basit bir örnekle devam edelim
veri = {
"kullanicilar": ["Ali", "Veli"],
"puanlar": {90, 85, 95}, # set — JSON bunu yapamaz
"detay": (1, 2, 3) # tuple — JSON bunu list yapar
}
# Kaydetme (serialization / pickling)
with open("veri.pkl", "wb") as f:
pickle.dump(veri, f)
# Yükleme (deserialization / unpickling)
with open("veri.pkl", "rb") as f:
yuklenen = pickle.load(f)
print(yuklenen)
print(type(yuklenen["puanlar"])) # <class 'set'> — korundu!
print(type(yuklenen["detay"])) # <class 'tuple'> — korundu!⚠️ Dikkat — GÜVENLİK UYARISI:
pickle.load()güvenilmeyen kaynaklardan gelen dosyalarda asla kullanılmamalı! Pickle dosyası rastgele kod çalıştırabilir. İnternetten indirilen, kullanıcıdan alınan veya bilinmeyen kaynaktan gelen pickle dosyalarını açma. Güvenli veri alışverişi için JSON kullan.
pickle vs JSON Karşılaştırma
| Özellik | JSON | pickle |
|---|---|---|
| Dil bağımsız | ✅ Evet | ❌ Sadece Python |
| İnsan okunabilir | ✅ Evet | ❌ Binary |
| Güvenlik | ✅ Güvenli | ⚠️ Tehlikeli olabilir |
| Python türleri | ❌ Sınırlı | ✅ Hepsini destekler |
| Hız | Orta | Hızlı |
| Dosya boyutu | Büyük | Küçük |
Kural: Veri alışverişi (API, config) → JSON. Dahili Python verileri (cache, model) → pickle (güvenilir kaynaktan).
Pratik: Adres Defteri Uygulaması
Öğrendiklerimizi birleştirerek JSON tabanlı bir adres defteri uygulaması yapalım:
import json
from pathlib import Path
from datetime import datetime
DOSYA_YOLU = Path("adres_defteri.json")
def defteri_yukle():
"""Adres defterini JSON dosyasından yükler."""
if not DOSYA_YOLU.exists():
return {"kisiler": [], "son_guncelleme": None}
try:
with open(DOSYA_YOLU, "r", encoding="utf-8") as f:
return json.load(f)
except json.JSONDecodeError:
print("Uyarı: Dosya bozuk, yeni defter oluşturuluyor.")
return {"kisiler": [], "son_guncelleme": None}
def defteri_kaydet(defter):
"""Adres defterini JSON dosyasına kaydeder."""
defter["son_guncelleme"] = datetime.now().isoformat()
with open(DOSYA_YOLU, "w", encoding="utf-8") as f:
json.dump(defter, f, indent=2, ensure_ascii=False)
print("Defter kaydedildi.")
def kisi_ekle(defter):
"""Yeni kişi ekler."""
ad = input("Ad: ").strip()
soyad = input("Soyad: ").strip()
telefon = input("Telefon: ").strip()
email = input("Email: ").strip()
if not ad or not soyad:
print("Ad ve soyad zorunludur!")
return
kisi = {
"ad": ad,
"soyad": soyad,
"telefon": telefon,
"email": email,
"eklenme": datetime.now().isoformat()
}
defter["kisiler"].append(kisi)
defteri_kaydet(defter)
print(f"{ad} {soyad} eklendi.")
def kisileri_listele(defter):
"""Tüm kişileri listeler."""
kisiler = defter["kisiler"]
if not kisiler:
print("Adres defteri boş.")
return
print(f"\n{'='*50}")
print(f"{'No':<4} {'Ad Soyad':<25} {'Telefon':<15}")
print(f"{'='*50}")
for i, kisi in enumerate(kisiler, 1):
tam_ad = f"{kisi['ad']} {kisi['soyad']}"
print(f"{i:<4} {tam_ad:<25} {kisi['telefon']:<15}")
print(f"{'='*50}")
print(f"Toplam: {len(kisiler)} kişi")
def kisi_ara(defter):
"""Kişi arar."""
arama = input("Aranacak isim: ").strip().lower()
bulunanlar = [
kisi for kisi in defter["kisiler"]
if arama in kisi["ad"].lower() or arama in kisi["soyad"].lower()
]
if not bulunanlar:
print("Sonuç bulunamadı.")
return
for kisi in bulunanlar:
print(f"\n📇 {kisi['ad']} {kisi['soyad']}")
print(f" 📞 {kisi['telefon']}")
print(f" 📧 {kisi['email']}")
def kisi_sil(defter):
"""Kişi siler."""
kisileri_listele(defter)
if not defter["kisiler"]:
return
try:
no = int(input("\nSilinecek kişi no: ")) - 1
if 0 <= no < len(defter["kisiler"]):
silinen = defter["kisiler"].pop(no)
defteri_kaydet(defter)
print(f"{silinen['ad']} {silinen['soyad']} silindi.")
else:
print("Geçersiz numara!")
except ValueError:
print("Sayı girin!")
def ana_menu():
"""Ana menü döngüsü."""
defter = defteri_yukle()
menu = """
📒 Adres Defteri
1. Kişi ekle
2. Kişileri listele
3. Kişi ara
4. Kişi sil
5. Çıkış
"""
while True:
print(menu)
secim = input("Seçiminiz: ").strip()
if secim == "1":
kisi_ekle(defter)
elif secim == "2":
kisileri_listele(defter)
elif secim == "3":
kisi_ara(defter)
elif secim == "4":
kisi_sil(defter)
elif secim == "5":
print("Güle güle!")
break
else:
print("Geçersiz seçim!")
if __name__ == "__main__":
ana_menu()Bu uygulama şunları gösteriyor:
json.dump() / json.load() ile dosya okuma/yazma
ensure_ascii=False ile Türkçe karakter desteği
indent=2 ile okunabilir JSON formatı
datetime.isoformat() ile tarih serialization
JSONDecodeError ile bozuk dosya kontrolü
pathlib.Path ile dosya varlık kontrolü
Oluşan JSON Dosyası
{
"kisiler": [
{
"ad": "Ali",
"soyad": "Yılmaz",
"telefon": "0532 123 4567",
"email": "ali@example.com",
"eklenme": "2024-06-15T14:30:00.123456"
},
{
"ad": "Ayşe",
"soyad": "Kaya",
"telefon": "0544 987 6543",
"email": "ayse@example.com",
"eklenme": "2024-06-15T14:31:15.789012"
}
],
"son_guncelleme": "2024-06-15T14:31:15.789012"
}JSON ile İleri Teknikler
JSON Schema Doğrulama (Basit)
import json
def json_dogrula(veri, sema):
"""Basit JSON doğrulama."""
hatalar = []
for alan, kural in sema.items():
if kural.get("zorunlu") and alan not in veri:
hatalar.append(f"'{alan}' alanı zorunlu")
continue
if alan in veri and "tip" in kural:
beklenen = kural["tip"]
gercek = type(veri[alan]).__name__
if gercek != beklenen:
hatalar.append(f"'{alan}': {beklenen} bekleniyor, {gercek} geldi")
return hatalar
sema = {
"ad": {"zorunlu": True, "tip": "str"},
"yas": {"zorunlu": True, "tip": "int"},
"email": {"zorunlu": False, "tip": "str"}
}
veri = {"ad": "Ali", "yas": "yirmi"} # yas string!
hatalar = json_dogrula(veri, sema)
for hata in hatalar:
print(f"❌ {hata}")
# ❌ 'yas': int bekleniyor, str geldiJSON Dosyasını Güvenli Güncelleme
import json
import tempfile
from pathlib import Path
def guvenli_json_kaydet(dosya_yolu, veri):
"""Atomik dosya yazma — bozuk dosya riski yok."""
yol = Path(dosya_yolu)
# Geçici dosyaya yaz
with tempfile.NamedTemporaryFile(
mode="w", dir=yol.parent, suffix=".tmp",
delete=False, encoding="utf-8"
) as tmp:
json.dump(veri, tmp, indent=2, ensure_ascii=False)
gecici_yol = Path(tmp.name)
# Geçici dosyayı asıl dosyaya taşı (atomik işlem)
gecici_yol.replace(yol)Bu pattern atomik yazma sağlar. Yazma sırasında hata oluşursa (elektrik kesilmesi, disk dolması) orijinal dosya bozulmaz.
💡 İpucu: Production'da JSON dosyalarını güncellerken her zaman atomik yazma kullan. Doğrudan dosyanın üzerine yazmak (
"w"modu) yazma sırasında hata olursa dosyayı bozar — ve bu veri kaybına yol açar.
CSV ile İleri Teknikler
Büyük CSV Dosyası İşleme
import csv
def csv_filtrele(girdi, cikti, kosul_fn, encoding="utf-8"):
"""Büyük CSV dosyasını filtreleyerek yeni dosyaya yazar."""
okunan = 0
yazilan = 0
with open(girdi, "r", encoding=encoding) as fin, \
open(cikti, "w", encoding=encoding, newline="") as fout:
okuyucu = csv.DictReader(fin)
yazici = csv.DictWriter(fout, fieldnames=okuyucu.fieldnames)
yazici.writeheader()
for satir in okuyucu:
okunan += 1
if kosul_fn(satir):
yazici.writerow(satir)
yazilan += 1
print(f"Okunan: {okunan}, Yazılan: {yazilan}")
# 18 yaşından büyükleri filtrele
csv_filtrele(
"ogrenciler.csv",
"yetiskinler.csv",
lambda satir: int(satir.get("yas", 0)) >= 18
)CSV'den JSON'a Dönüştürme
import csv
import json
def csv_to_json(csv_yolu, json_yolu):
"""CSV dosyasını JSON'a çevirir."""
veriler = []
with open(csv_yolu, "r", encoding="utf-8") as f:
okuyucu = csv.DictReader(f)
for satir in okuyucu:
veriler.append(satir)
with open(json_yolu, "w", encoding="utf-8") as f:
json.dump(veriler, f, indent=2, ensure_ascii=False)
print(f"{len(veriler)} kayıt dönüştürüldü")
csv_to_json("ogrenciler.csv", "ogrenciler.json")Özet
Bu derste veri serialization formatlarını ve Python araçlarını öğrendik:
JSON en yaygın veri alışveriş formatı.
json.dumps()/json.loads()string işlemleri,json.dump()/json.load()dosya işlemleri için kullanılır.ensure_ascii=Falseile Türkçe karakterleri destekle,indentile okunabilir format oluştur.JSON ↔ Python dönüşümlerinde
True→true,None→nullolur.tuple→list'e dönüşür,setvedatetimedoğrudan desteklenmez —defaultparametresi ile custom serialization yaz.CSV tablo verileri için kullanılır.
csv.reader()/csv.writer()liste bazlı,csv.DictReader()/csv.DictWriter()sözlük bazlı işlem yapar.delimiterparametresi ile farklı ayırıcıları destekle.configparser INI formatındaki yapılandırma dosyalarını okur/yazar. Basit key-value ayarlar için ideal.
pickle her Python nesnesini serialize edebilir ama güvenilmeyen kaynaklarda asla kullanılmamalı — rastgele kod çalıştırma riski var. İç kullanım (cache, model kaydetme) için uygun.
Atomik yazma pattern'i (geçici dosyaya yaz → taşı) production'da veri bozulmasını engeller.
AI Asistan
Sorularını yanıtlamaya hazır