Python 3.15, 9 Ekim 2026 tarihinde yayımlandı ve dilin kendisinde beş büyük yenilik getirdi: lazy anahtar kelimesiyle açık tembel içe aktarma (PEP 810), değiştirilemez sözlük tipi frozendict (PEP 814), yerleşik sentinel tipi (PEP 661), ortamdan bağımsız varsayılan UTF-8 kodlaması (PEP 686) ve comprehension içinde * ile ** açma (PEP 798). Standart kütüphanede yeni profiling paketi ve Tachyon örnekleme profilleyicisi, daha renkli komut satırı çıktıları ve daha yardımcı hata mesajları öne çıkıyor.
Bu yazı yalnızca resmî "What's New in Python 3.15" belgesine dayanır ve önemli değişiklikleri çalışan örneklerle anlatır. Tüm kodlar 3.15 serisinin bu yazı yazılırken en güncel bakım sürümü olan 3.15.2 ile çalıştırıldı. Kaldırılan API'ler, yeni kullanımdan kaldırma uyarıları ve kodunuzu taşırken dikkat etmeniz gereken noktalar da sonda ayrı bölümlerde.
Kısa özet
| Alan | Değişiklik | Kaynak |
|---|---|---|
| Dil | lazy import ve lazy from ... import | PEP 810 |
| Yerleşik tip | frozendict: değiştirilemez, hash edilebilir sözlük | PEP 814 |
| Yerleşik tip | sentinel: benzersiz işaretçi değerler | PEP 661 |
| Kodlama | open() ve diğer G/Ç için varsayılan UTF-8 | PEP 686 |
| Söz dizimi | [*L for L in listeler] ve {**d for d in sozlukler} | PEP 798 |
| Başlangıç | .start dosyaları; .pth içindeki import satırları sessizce kullanımdan kalktı | PEP 829 |
| Profil | profiling paketi, profiling.sampling (Tachyon) | PEP 799 |
| C API | Free-threaded yapılar için kararlı ABI (abi3t) | PEP 803 |
| Derleme | Frame pointer varsayılan olarak açık | PEP 831 |
| Tip sistemi | TypeForm, TypedDict closed ve extra_items, disjoint_base | PEP 747, 728, 800 |
lazy import: modülü ilk kullanımda yüklemek

Büyük uygulamaların açılışını yavaşlatan nedenlerden biri içe aktarma sistemidir: her import dosyayı bulur, okur, derler ve üst düzey kodu çalıştırır; o çalıştırmada modül hiç kullanılmasa bile. Geliştiriciler bu yüzden import satırlarını fonksiyonların içine taşımak gibi yollara başvuruyordu. 3.15 ile gelen lazy yumuşak anahtar kelimesi (soft keyword) bu ihtiyacı doğrudan karşılar: import satırı dosyanın başında kalır, ama modül adı ilk kez kullanıldığında yüklenir. O ana kadar ad, hafif bir vekil (proxy) nesneye bağlıdır.
lazy import json
lazy from pathlib import Path
import sys
print('json' in sys.modules)
# çıktı: False
veri = json.loads('{"şehir": "Ankara"}')
print(veri['şehir'])
# çıktı: Ankara
print('json' in sys.modules)
# çıktı: True
print(Path('rapor.txt').suffix)
# çıktı: .txtVekil nesnenin tipi types.LazyImportType olarak dışa açılmıştır; ad kullanıldığı anda gerçek modülle yer değiştirir:
import types
lazy import json
print(type(globals()['json']) is types.LazyImportType)
# çıktı: True
json.dumps(1)
print(type(globals()['json']) is types.LazyImportType)
# çıktı: FalseTembel içe aktarmanın kuralları belgelerde açıkça sayılmış. lazy yalnızca modül düzeyinde kullanılabilir; fonksiyon, sınıf gövdesi ya da try/except/finally bloğu içinde SyntaxError verir. Yıldızlı içe aktarma (lazy from m import *) ve __future__ içe aktarmaları tembel olamaz.
def yukle():
lazy import json
# File "ornek.py", line 2
# lazy import json
# ^^^^^^^^^^^^^^^^
# SyntaxError: lazy import not allowed inside functionsYükleme başarısız olursa (örneğin modül yoksa) hata import satırında değil, adın ilk kullanıldığı yerde ortaya çıkar. Traceback hem kullanım yerini hem de asıl import satırını gösterir. Yakalanan istisnanın __cause__ özniteliği tembel çözümlemenin hatasını taşır:
lazy import olmayan_modul
print('Başladı')
try:
olmayan_modul.calistir()
except ImportError as e:
print(type(e).__name__, '|', e)
print(type(e.__cause__).__name__, '|', e.__cause__)
# çıktı: Başladı
# çıktı: ModuleNotFoundError | No module named 'olmayan_modul'
# çıktı: ImportError | lazy import of 'olmayan_modul' raised an exception during resolutionKaynak kodu değiştirmeden tüm içe aktarmaları tembel yapmak için -X lazy_imports=all komut satırı seçeneği ya da PYTHON_LAZY_IMPORTS ortam değişkeni vardır; varsayılan değer normal, yalnızca lazy yazılan satırları tembel yapar. Çalışma anında sys.set_lazy_imports() ile mod değiştirilebilir, sys.set_lazy_imports_filter() ile hangi modüllerin tembel yükleneceğine karar veren bir filtre fonksiyonu tanımlanabilir. Eski sürümleri de destekleyen kod için modül düzeyinde __lazy_modules__ = ['json'] listesi tanımlamak, o modüllerin normal import satırlarını tembel hâle getirir. Tembel bir içe aktarma kendini dolaylı yoldan yeniden içe aktarmaya çalışırsa yeni ImportCycleError istisnası fırlatılır. İçe aktarma sisteminin genel işleyişi için modül ve paket import yazısına bakın.
frozendict: değiştirilemez sözlük
frozendict, oluşturulduktan sonra değiştirilemeyen yeni bir yerleşik tiptir. dict sınıfının alt sınıfı değildir, doğrudan object sınıfından türer. Tüm anahtar ve değerleri hash edilebilirse kendisi de hash edilebilir; bu sayede sözlük anahtarı ya da küme elemanı olabilir. Ekleme sırasını korur ama eşitlik karşılaştırması sıraya bakmaz.
ayar = frozendict(dil='tr', tema='koyu')
print(ayar)
# çıktı: frozendict({'dil': 'tr', 'tema': 'koyu'})
print(ayar['dil'])
# çıktı: tr
onbellek = {ayar: 'hazır'}
print(onbellek[frozendict(tema='koyu', dil='tr')])
# çıktı: hazır
print(ayar == {'dil': 'tr', 'tema': 'koyu'})
# çıktı: True
print(isinstance(ayar, dict))
# çıktı: False
ayar['dil'] = 'en'
# Traceback (most recent call last):
# File "ornek.py", line 13, in <module>
# ayar['dil'] = 'en'
# ~~~~^^^^^^^
# TypeError: 'frozendict' object does not support item assignmentisinstance(x, dict) kontrolü frozendict için False döndüğünden, sürüm notları bu tür kontrolleri isinstance(x, (dict, frozendict)) ya da her eşleme tipini kabul eden isinstance(x, collections.abc.Mapping) biçimine güncellemeyi önerir. copy, json, pickle, pprint ve decimal gibi modüller frozendict kabul edecek şekilde güncellendi. json modülüne eklenen array_hook parametresiyle birlikte JSON verisini tamamen değiştirilemez bir yapıya çevirebilirsiniz:
import json
veri = json.loads('{"ad": "nokta", "konum": [1, 2]}',
object_pairs_hook=frozendict, array_hook=tuple)
print(veri)
# çıktı: frozendict({'ad': 'nokta', 'konum': (1, 2)})Sözlük metotlarının ayrıntıları için Python sözlük metotları yazısına bakabilirsiniz.
sentinel: "değer verilmedi" işaretçisi
Bir parametrenin hiç verilmediğini None değerinden ayırt etmek için uzun zamandır EKSIK = object() gibi özel nesneler kullanılıyordu. Bunların gösterimi anlaşılmazdı ve tip ipuçlarında kullanılamıyordu. Yeni sentinel tipi kısa bir gösterime sahip benzersiz nesneler üretir: kopyalandığında kimliği korunur, tip ifadelerinde | işleciyle kullanılabilir ve modülden adıyla içe aktarılabiliyorsa pickle ile saklanabilir. Belgeler sentinel nesnelerin is ile karşılaştırılmasını, adının atandığı değişkenle aynı olmasını önerir; sentinel her zaman doğru (truthy) kabul edilir ve alt sınıflanamaz.
EKSIK = sentinel('EKSIK')
def bul(sozluk, anahtar, varsayilan=EKSIK):
if anahtar in sozluk:
return sozluk[anahtar]
if varsayilan is EKSIK:
raise KeyError(anahtar)
return varsayilan
print(EKSIK)
# çıktı: EKSIK
print(bul({'a': None}, 'a'))
# çıktı: None
print(bul({}, 'b', None))
# çıktı: None
print(bool(EKSIK))
# çıktı: TrueBu örnekte None hem geçerli bir sözlük değeri hem de geçerli bir varsayılan olabiliyor; "argüman verilmedi" durumunu ayırmanın tek temiz yolu ayrı bir işaretçidir. Tip ipuçlarında def f(x: int | EKSIK = EKSIK) biçimi kullanılabilir; tip ipuçları için type hints rehberine bakın.
Comprehension içinde * ve ** ile açma
PEP 448 ile gelen açma söz dizimi artık liste, küme ve sözlük comprehension ifadelerinde ve generator ifadelerinde de geçerli. İç içe listeleri düzleştirmek için iki for yazmaya ya da itertools.chain.from_iterable() kullanmaya gerek kalmıyor:
siparisler = [['kalem', 'defter'], ['silgi'], []]
print([*s for s in siparisler])
# çıktı: ['kalem', 'defter', 'silgi']
etiketler = [{'python', 'web'}, {'web', 'sunucu'}]
print(sorted({*e for e in etiketler}))
# çıktı: ['python', 'sunucu', 'web']
ayarlar = [{'port': 80}, {'host': 'localhost'}, {'port': 8080}]
print({**a for a in ayarlar})
# çıktı: {'port': 8080, 'host': 'localhost'}Sözlük örneğinde aynı anahtar birden çok kez geçtiğinde son değer kazanır; port 8080 oldu. Ayrıntılar ve iç içe comprehension ile karşılaştırma için list comprehension yazısına bakabilirsiniz.
Varsayılan kodlama artık UTF-8
3.15 ile Python, sistemin yerel ayarından bağımsız olarak UTF-8 kodlamasını varsayılan kabul ediyor. open('dosya.txt') gibi encoding verilmeyen G/Ç işlemleri artık UTF-8 kullanıyor. Bu değişiklik özellikle Windows'ta önemli; çünkü önceden varsayılan, sistemin kod sayfasıydı. Türkçe Windows kullanan bu bilgisayarda yerel kodlama hâlâ cp1254 görünüyor, ama açılan dosya UTF-8 ile açılıyor:
import locale, sys
print(sys.flags.utf8_mode)
# çıktı: 1
print(locale.getencoding())
# çıktı: cp1254
with open('ornek.txt', 'w') as f:
print(f.encoding)
# çıktı: utf-8Sürüm notları, sürümler arası en iyi uyumluluk için encoding argümanını her zaman açıkça yazmayı önermeyi sürdürüyor. Yerel kodlamayı bilerek kullanmak isteyenler encoding='locale' yazabilir (3.10'dan beri destekleniyor). Eski davranışa dönmek için PYTHONUTF8=0 ortam değişkeni ya da -X utf8=0 seçeneği kullanılabilir. Konunun Türkçe karakterlerle ilgili tarafı Unicode ve Türkçe karakter, dosya tarafı dosya okuma yazma yazısında.
Daha yardımcı hata mesajları
3.15 ile AttributeError önerileri genişledi. Yerleşik bir tipte yakın bir ad bulunamadığında yorumlayıcı JavaScript, Java, Ruby ve C# gibi dillerdeki yaygın metot adlarından oluşan bir tabloya bakıp Python karşılığını öneriyor. Karşılık bir metot değil de bir dil yapısıysa öneri o yapıyı tarif ediyor; değiştirilemez bir tipte değiştiren bir metot çağrıldığında değiştirilebilir karşılığı öneriliyor:
ayar = {}
ayar.put('dil', 'tr')
# Traceback (most recent call last):
# File "ornek.py", line 2, in <module>
# ayar.put('dil', 'tr')
# ^^^^^^^^
# AttributeError: 'dict' object has no attribute 'put'. Use d[k] = v.renkler = ('kırmızı', 'mavi')
renkler.append('yeşil')
# Traceback (most recent call last):
# File "ornek.py", line 2, in <module>
# renkler.append('yeşil')
# ^^^^^^^^^^^^^^
# AttributeError: 'tuple' object has no attribute 'append'. Did you mean to use a 'list' object?Ayrıca bir nesnenin özniteliği üzerinden erişilebilen bir ad istendiğinde öneri '.inner.area' gibi iç yolu gösteriyor; delattr() ve del nesne.ad başarısız olduğunda da benzer ad önerisi geliyor. Önerilerin, istisna nesnesinin str() değerinde değil traceback görüntülenirken eklendiğini bilmekte fayda var: except AttributeError as e: print(e) yazdığınızda öneri satırı görünmez. Bu ve önceki sürümlerdeki mesajların tamamı için sık hata mesajları yazısına bakın.
Standart kütüphanede öne çıkanlar

- profiling paketi:
profiling.tracing(eskicProfile) ve yeni örnekleme profilleyicisiprofiling.sampling(Tachyon) tek ad alanında toplandı. Tachyon çalışan bir sürece PID ile bağlanabiliyor, duvar saati, CPU, GIL ve istisna modlarında örnek topluyor; flame graph, heatmap ve Firefox Profiler biçiminde çıktı üretebiliyor.cProfilegeriye uyumluluk için takma ad olarak kalıyor;profilemodülü kullanımdan kaldırıldı ve 3.17'de silinecek. - argparse: yanlış yazılan seçimler için öneri varsayılan olarak açık; ayrıntılar argparse rehberinde.
- re:
re.match()adının kafa karıştırıcı olması nedeniyle aynı işi yapanre.prefixmatch()eklendi vematch()yumuşak kullanımdan kaldırıldı (soft deprecated). Eski ad silinmeyecek. - unicodedata: Unicode veritabanı 17.0.0 sürümüne güncellendi;
block(),iter_graphemes(),isxidstart()veisxidcontinue()eklendi. - math.integer: tam sayı argümanlı matematik fonksiyonları için yeni modül (PEP 791).
- collections:
Counternesneleri için simetrik fark işleci^eklendi. - asyncio:
TaskGroup.cancel()ile bir görev grubu erkenden sonlandırılabiliyor. - unittest:
assertLogs()bir formatter alabiliyor;assertWarns()eşleşmeyen uyarıları artık yutmuyor. - Daha fazla renk: argparse, sqlite3 kabuğu, timeit, difflib, http.server,
python --helpve birçok modülün komut satırı yardımı renkli.
import re
print(re.prefixmatch(r'\d+', '2026 yılı'))
# çıktı: <re.Match object; span=(0, 4), match='2026'>
print(re.prefixmatch(r'\d+', 'yıl 2026'))
# çıktı: None
print(re.search(r'\d+', 'yıl 2026'))
# çıktı: <re.Match object; span=(4, 8), match='2026'>import unicodedata
from math import integer
from collections import Counter
print(unicodedata.unidata_version)
# çıktı: 17.0.0
print(unicodedata.block('ğ'))
# çıktı: Latin Extended-A
print(integer.isqrt(50))
# çıktı: 7
print(Counter(elma=3, armut=1) ^ Counter(elma=1, kiraz=2))
# çıktı: Counter({'elma': 2, 'kiraz': 2, 'armut': 1})prefixmatch() yalnızca metnin başından eşleşme arar, search() metnin her yerine bakar. Belgeler eski sürümleri de destekleyen kodda match() kullanmayı sürdürmeyi, yalnızca 3.15 hedefleyen yeni kodda prefixmatch() yazmayı önerir. Düzenli ifadelerin geri kalanı için re modülü yazısına bakabilirsiniz.
Kaldırılanlar ve kodunuzu bozabilecek değişiklikler

Önceki sürümlerde kullanımdan kaldırılmak üzere işaretlenen bazı API'ler 3.15 ile silindi ya da hata vermeye başladı. Kodunuzu yükseltmeden önce özellikle şunlara bakın:
| Alan | Değişiklik |
|---|---|
| datetime | strptime() biçiminde yıl olmadan %d kullanmak artık ValueError |
| sqlite3 | connect() fonksiyonunda database dışındaki tüm parametreler yalnızca anahtar kelimeyle |
| argparse | add_argument('-f', '-foo') için dest artık 'foo' |
| base64 | urlsafe_b64decode() artık dolgu (padding) istemiyor |
| http.server | CGIHTTPRequestHandler ve --cgi seçeneği kaldırıldı |
| pathlib | PurePath.is_reserved() kaldırıldı; os.path.isreserved() kullanın |
| glob | Belgelenmemiş glob0() ve glob1() kaldırıldı |
| sre_* | sre_compile, sre_constants, sre_parse modülleri kaldırıldı |
| typing | NamedTuple için anahtar kelime söz dizimi ve alansız TypedDict("TD") biçimi kaldırıldı |
| importlib | Loader.load_module() kaldırıldı; exec_module() kullanın |
| modüller | __cached__ özniteliği artık ayarlanmıyor; __spec__.cached kullanın |
from datetime import datetime
print(datetime.strptime('2026-11-07', '%Y-%m-%d').date())
# çıktı: 2026-11-07
datetime.strptime('07.11', '%d.%m')
# ValueError: Day of month directive '%d' may not be used without a year directive. Parsing dates involving a day of month without a year is ambiguous and fails to parse leap day. Add a year to the input and format. See https://github.com/python/cpython/issues/70647.import sqlite3
baglanti = sqlite3.connect(':memory:', 5.0)
# TypeError: connect() takes at most 1 positional arguments (2 given)Bu iki örnekte traceback'in yalnızca son satırını gösterdik. sqlite3 için çözüm zaman aşımını sqlite3.connect(':memory:', timeout=5.0) biçiminde anahtar kelimeyle vermektir; modülün geri kalanı sqlite3 rehberinde. Tarih ayrıştırmada yıl içermeyen girdiye bir yıl eklemek gerekir; ayrıntılar datetime yazısında.
Yeni kullanımdan kaldırma uyarıları
profilemodülü 3.17 sürümünde kaldırılacak; yerineprofiling.tracingkullanın.-bve-bbkomut satırı seçenekleri 3.17 ile etkisiz hâle gelecek.- argparse, csv, json, logging, re, pickle gibi birçok standart modülün
__version__,versionveVERSIONöznitelikleri 3.20 sürümünde kaldırılacak; sürüm içinsys.version_infokullanın. hashlibyapıcılarındastring=anahtar kelimesi 3.19 sürümünde kaldırılacak.collections.abc.ByteStringvetyping.ByteStringartık içe aktarıldığında bileDeprecationWarningveriyor; 3.17 sürümünde kaldırılacaklar..pthdosyalarındakiimportsatırları sessizce kullanımdan kaldırıldı; aynı adlı.startdosyası varsa yok sayılıyorlar.
Tüm liste için resmî Deprecations sayfası güncel tutuluyor.
Yorumlayıcı, derleme ve dağıtım tarafı
Deneysel JIT derleyicisi önemli ölçüde güncellendi; sürüm notları pyperformance kıyaslamalarında x86-64 Linux üzerinde yüzde 7-8, AArch64 macOS üzerinde yüzde 11-12 geometrik ortalama hızlanma raporluyor. Resmî Windows 64 bit ikili dosyaları artık Visual Studio 2026 ile gelen kuyruk çağrılı (tail-calling) yorumlayıcıyı kullanıyor; macOS ikili dosyaları free-threading desteğini varsayılan olarak kuruyor. CPython artık destekleyen platformlarda frame pointer ile derleniyor; bu, sistem profilleyicileri ve hata ayıklayıcıların yığın izini daha güvenilir çıkarmasını sağlıyor. C eklentisi yazanlar için free-threaded yapılarla uyumlu kararlı ABI (abi3t) geldi. Free-threading konusunun genel çerçevesi için threading ve multiprocessing yazısına bakabilirsiniz.
3.15.2 bakım sürümünde iki önemli düzeltme öne çıkıyor: paket ve alt modülleri aynı anda ilk kez içe aktaran iş parçacıkları arasında 3.15.0 ile ortaya çıkan kilitlenme (deadlock) riski giderildi; ssl modülü ise ele geçirilmiş belirli eMudhra ara sertifikalarını içeren zincirleri, uygulama kendi kök sertifika paketini verse bile reddediyor.
Yükseltme kontrol listesi
- Projeniz için yeni bir sanal ortamı 3.15 ile oluşturun ve testlerinizi çalıştırın; unittest çıktısında yeni görünen uyarılara bakın.
encodingvermeden dosya açtığınız yerleri bulun; Windows'ta eski kod sayfasıyla yazılmış dosyaları okuyorsanızencodingdeğerini açıkça yazın.isinstance(x, dict)kontrollerininfrozendictile ilişkisini değerlendirin.sqlite3.connect(),strptime()ve argparsedestdeğişikliklerinin kodunuzu etkileyip etkilemediğini kontrol edin.python -W error::DeprecationWarningile çalıştırıp kullanımdan kalkan API'leri erkenden yakalayın.- Açılış süresi önemliyse ağır modülleri
lazy importile işaretlemeyi deneyin.
Sık Sorulan Sorular
Python 3.15 ne zaman çıktı?
Sürüm notlarına göre 9 Ekim 2026 tarihinde. Bu yazı 3.15.2 bakım sürümüyle denendi.
lazy import her projede kullanılmalı mı?
Zorunlu değil. Belgeler bu özelliğin özellikle çok sayıda modülü üst düzeyde içe aktaran ama her çalıştırmada bunların bir kısmını kullanan uygulamalarda açılış gecikmesini azalttığını belirtir. Hatanın import satırında değil ilk kullanımda çıkacağını unutmayın.
frozendict ile MappingProxyType arasındaki fark nedir?
types.MappingProxyType var olan bir sözlüğün salt okunur görünümüdür; alttaki sözlük değişirse görünüm de değişir. frozendict ise kendi verisini tutan, oluşturulduktan sonra değişmeyen bağımsız bir tiptir ve hash edilebilir olabilir.
Kodum 3.15 öncesi sürümlerde de çalışmalı, ne yapmalıyım?
lazy anahtar kelimesi, frozendict, sentinel ve comprehension içinde açma eski sürümlerde söz dizimi ya da ad hatası verir. Tembel içe aktarma için belgelerin önerdiği __lazy_modules__ listesi eski sürümlerde sıradan bir değişken olarak kalır; diğer özellikler için sürüm kontrolü ya da eski yazım biçimleri gerekir.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Python öğrenme rehberi · Sık hata mesajları · Unicode ve UTF-8 · Sözlük metotları · List comprehension · Modül ve import