f-string (biçimlendirilmiş metin literali), başına f veya F konan bir metindir; süslü parantez içine yazdığınız Python ifadeleri çalışma anında hesaplanıp metne yerleştirilir: f'{ad} {yas} yaşında'. Parantez içinde ifadeden sonra = (hata ayıklama), !r/!s/!a (dönüşüm) ve : ile başlayan bir biçim belirteci gelebilir. {fiyat:,.2f} binlik ayırıcı ve iki ondalık basamak, {ad:<10} 10 karakterlik alanda sola hizalama, {oran:.1%} yüzde gösterimi verir. Python 3.14 ile gelen t-string'ler (t'...') aynı sözdizimini kullanır ama metin yerine işlenebilir bir Template nesnesi üretir.
Bu yazıda f-string sözdizimini, biçim belirtimi mini dilini (Format Specification Mini-Language), str.format() ve eski % biçimlendirmesiyle farklarını ve t-string'leri resmî Python belgelerine (Lexical analysis, Built-in Types, string ve string.templatelib modülleri, Tutorial) dayanarak anlatıyoruz. Bütün örnekler Python 3.15.2 ile çalıştırıldı ve çıktılar gerçek çıktılardır. Metin metotları için string metotları yazısına bakabilirsiniz.
f-string sözdizimi

Normal metin literallerinden farklı olarak f-string'lerin sabit bir değeri yoktur. İçlerindeki yer değiştirme alanları (replacement field) süslü parantezlerle sınırlanır ve her biri çalışma anında, f-string'in bulunduğu yerin kapsamında, soldan sağa değerlendirilen bir ifade içerir. Değişken adı, metot çağrısı, aritmetik, indeksleme gibi her ifade yazılabilir; yalnızca boş ifadeye izin verilmez. Metne gerçek bir süslü parantez koymak için onu ikiler: {{ ve }}.
ad = 'Elif'
yas = 29
print(f'{ad} {yas} yaşında.') # çıktı: Elif 29 yaşında.
print(F'{ad.upper()} / {yas * 12} ay') # çıktı: ELIF / 348 ay
print(f'{{süslü}} parantez: {ad}') # çıktı: {süslü} parantez: Elif
fiyatlar = {'çay': 15}
print(f"Çay: {fiyatlar['çay']} TL") # çıktı: Çay: 15 TL
print(f"Çay: {fiyatlar["çay"]} TL") # çıktı: Çay: 15 TLSon satır Python 3.12 öncesinde sözdizimi hatasıydı. Belgelere göre 3.12 ile (PEP 701) f-string içindeki ifadelere konan birçok kısıtlama kaldırıldı: Artık yer değiştirme alanında dıştaki tırnak türünü yeniden kullanabilir, ters eğik çizgi (\n gibi) yazabilir, ifadeyi birden çok satıra bölüp yorum ekleyebilir ve f-string'leri iç içe kullanabilirsiniz. Belgeler taşınabilir programların 5 seviyeden fazla iç içe f-string kullanmamasını önerir. Boş bir alan (f'{}') ise SyntaxError: f-string: valid expression required before '}' verir.
kelimeler = ['elma', 'armut']
print(f"Liste: {", ".join(kelimeler)}") # çıktı: Liste: elma, armut
print(f"Satırlar:\n{"\n".join(kelimeler)}")
# çıktı: Satırlar:
# çıktı: elma
# çıktı: armut
toplam = f'{
2 + 3 # yer değiştirme alanında yorum
}'
print(toplam) # çıktı: 5Parantez gerektiren ifadeler
Lexical analysis belgesine göre lambda ve atama ifadesi (:=) bir yer değiştirme alanında ancak açık parantez içinde kullanılabilir; aksi hâlde : ve = karakterleri biçim belirteci veya hata ayıklama işareti olarak yorumlanır. Koşullu ifade ise parantezsiz yazılabilir.
print(f'{(yarim := 1 / 2)}, {yarim * 42}') # çıktı: 0.5, 21.0
print(f'{(lambda y: y * 2)(5)}') # çıktı: 10
x = 5
print(f'{"büyük" if x > 3 else "küçük"}') # çıktı: büyükDönüşüm belirteçleri: !s, !r, !a
Varsayılan olarak alanın değeri str() ile metne çevrilir. Dönüşüm belirteci bunu değiştirir: !s str(), !r repr(), !a ascii() uygular. repr() yorumlayıcının okuyabileceği gösterimi verir (metinler tırnaklı görünür), bu yüzden hata ayıklamada ve kayıt mesajlarında boş veya boşluklu değerleri fark etmenizi sağlar. !a ise ASCII dışı karakterleri kaçış dizilerine çevirir; Türkçe harflerin nasıl göründüğüne bakın:
from fractions import Fraction
metin = 'çay '
print(f'[{metin}]') # çıktı: [çay ]
print(f'[{metin!r}]') # çıktı: ['çay ']
print(f'[{metin!a}]') # çıktı: ['\xe7ay ']
uc = Fraction(1, 3)
print(f'{uc} / {uc!r}') # çıktı: 1/3 / Fraction(1, 3)Hata ayıklama için = belirteci
Python 3.8 ile gelen = belirteci, ifadenin metnini, eşittir işaretini ve değerini birlikte yazar. Belgelere göre ifadenin önündeki, içindeki ve sonrasındaki boşluklar ile eşittir işaretinden sonraki boşluklar korunur. Biçim belirteci verilmediğinde değer bu kez repr() ile gösterilir; bu yüzden metinler tırnaklı çıkar. İsterseniz dönüşüm ve biçim belirtecini ='ten sonra ekleyebilirsiniz.
x = 5
ad = 'Can'
oran = 0.4567
print(f'{x=}') # çıktı: x=5
print(f'{x = }') # çıktı: x = 5
print(f'{x * 2 = }') # çıktı: x * 2 = 10
print(f'{ad=}') # çıktı: ad='Can'
print(f'{ad=!s}') # çıktı: ad=Can
print(f'{oran=:.2f}') # çıktı: oran=0.46Biçim belirtimi mini dili

İki noktadan sonraki kısım biçim belirtecidir (format spec) ve format() yerleşik fonksiyonuna ikinci argüman olarak aktarılır; yani f'{x:.2f}' ile format(x, '.2f') aynı sonucu verir. string modülünün belgelediği genel yapı şöyledir:
[[dolgu]hizalama][işaret]["z"]["#"]["0"][genişlik][gruplama]["." hassasiyet][gruplama][tip]Parçaların hepsi isteğe bağlıdır ve sıraları sabittir. Belgelere göre boş bir belirteç, değere str() uygulanmış gibi sonuç verir. Her tip belirteci kendi kurallarıyla yorumlayabilir; aşağıdakiler yerleşik sayı ve metin tiplerinin desteklediği ortak seçeneklerdir.
Genişlik, dolgu ve hizalama
Genişlik, alanın toplam en küçük karakter sayısıdır; değer daha kısaysa dolgu karakteriyle tamamlanır, daha uzunsa kesilmez. < sola, > sağa, ^ ortaya hizalar; = dolguyu işaretten sonra, rakamlardan önce koyar ve yalnızca sayılarda geçerlidir. Çoğu nesne varsayılan olarak sola, sayılar sağa hizalanır. Hizalama işaretinden önce herhangi bir karakter dolgu olarak verilebilir; tek istisna, f-string ve str.format() içinde süslü parantezin dolgu olamamasıdır. İşaret seçeneği yalnızca sayılarda çalışır: + her zaman işaret, boşluk ise pozitif sayılarda baştaki bir boşluk koyar.
print(f'|{"sol":<10}|{"sağ":>10}|{"orta":^10}|') # çıktı: |sol | sağ| orta |
print(f'|{"orta":*^10}|{42:>6}|{42:<6}|') # çıktı: |***orta***| 42|42 |
print(f'|{3.14159:10.3f}|{-7:+}|{7:+}|{7: }|') # çıktı: | 3.142|-7|+7| 7|
print(f'|{-42:=8}|{-42:08}|') # çıktı: |- 42|-0000042|Sayı tipleri, hassasiyet ve gruplama
Tip harfi değerin nasıl gösterileceğini belirler. Tam sayılarda d onluk, b ikilik, o sekizlik, x/X on altılık gösterim verir; # seçeneği 0b, 0o, 0x öneklerini ekler. Ondalık sayılarda f sabit noktalı, e bilimsel, g genel gösterimdir, % ise sayıyı 100 ile çarpıp yüzde işaretiyle yazar. Hassasiyet f ve %'de noktadan sonraki basamak sayısıdır; belirtilmezse 6 kullanılır. Gruplama seçeneği , veya _ her üç basamakta bir ayırıcı koyar; b, o, x tiplerinde _ her dört basamakta bir eklenir. Python 3.14'ten beri gruplama ondalık kısma da uygulanabiliyor. z seçeneği (3.11) yuvarlamadan sonra oluşan negatif sıfırı pozitif sıfıra çevirir.
n = 1234567.891
print(f'{n:.2f}') # çıktı: 1234567.89
print(f'{n:,.2f}') # çıktı: 1,234,567.89
print(f'{n:_.2f}') # çıktı: 1_234_567.89
print(f'{n:.2e}') # çıktı: 1.23e+06
print(f'{n:_._f}') # çıktı: 1_234_567.891_000
print(f'{0.4567:.1%}') # çıktı: 45.7%
print(f'{255:d} {255:x} {255:#x} {255:o} {255:b} {255:_b}') # çıktı: 255 ff 0xff 377 11111111 1111_1111
print(f'{7:03d}') # çıktı: 007
print(f'{-0.0001:.2f} {-0.0001:z.2f}') # çıktı: -0.00 0.00Belgelere göre yuvarlama, round() yerleşik fonksiyonuyla aynı kuralı izler. Ondalık sayıların ikilik tabanda tam gösterilememesinden kaynaklanan yuvarlama sürprizleri için sayılar yazısına bakın.
Türkçe para biçimi
Biçim mini dilinde ondalık ayırıcı her zaman noktadır. Türkiye'de alışılmış 1.234.567,89 biçimi için belgeler, yerel ayara duyarlı n tipini ve locale.setlocale() ile ayarlanan yerel ayarı önerir; ancak bu, sistemde ilgili yerel ayarın kurulu olmasına bağlıdır. Yerel ayardan bağımsız basit bir yol, önce standart biçimde yazıp sonra ayırıcıların yerini değiştirmektir:
def tl(tutar):
metin = f'{tutar:,.2f}' # 1,234,567.89
return metin.replace(',', '_').replace('.', ',').replace('_', '.') + ' TL'
print(tl(1234567.891)) # çıktı: 1.234.567,89 TL
print(tl(0.5)) # çıktı: 0,50 TLMetinlerde hassasiyet ve dinamik genişlik
Metin değerlerinde hassasiyet, en fazla kaç karakterin kullanılacağını belirtir; yani {metin:.7} metni 7 karaktere keser. Belirtecin içine başka yer değiştirme alanları da koyabilirsiniz; bu iç alanlar önce değerlendirilir, böylece genişlik ve hassasiyeti çalışma anında seçersiniz. Belgelere göre bu iç alanlar bir seviyeden daha derine inemez. Hizalı tablo yazdırmak için en uzun adın uzunluğunu bulup genişlik olarak vermek yaygın bir kullanımdır:
print(f'{"Merhaba dünya":.7}') # çıktı: Merhaba
genislik, hassasiyet = 12, 3
print(f'[{14.3:{genislik}.{hassasiyet}f}]') # çıktı: [ 14.300]
urunler = [('Kalem', 12.5), ('Defter', 30), ('Silgi', 5.75)]
w = max(len(ad) for ad, _ in urunler)
for ad, fiyat in urunler:
print(f'{ad:<{w}} {fiyat:>8.2f}')
# çıktı: Kalem 12.50
# çıktı: Defter 30.00
# çıktı: Silgi 5.75Tarih ve diğer tiplerin kendi biçimleri
Biçimlendirme işi aslında değerin kendi __format__() metoduna bırakılır, bu yüzden her tip mini dili kendine göre yorumlayabilir. datetime nesneleri belirteci strftime() kodları olarak okur. Tarih ve saat işlemlerinin tamamı datetime yazısında.
import datetime
d = datetime.date(2026, 11, 7)
saat = datetime.datetime(2026, 11, 7, 9, 5)
print(f'{d:%d.%m.%Y}') # çıktı: 07.11.2026
print(f'{saat:%H:%M}') # çıktı: 09:05
print(f'{d!r}') # çıktı: datetime.date(2026, 11, 7)Tipin desteklemediği bir belirteç ValueError verir. Örneğin metne tam sayı tipi uygulamak: f'{"metin":d}' ifadesi ValueError: Unknown format code 'd' for object of type 'str' hatasıyla sonuçlanır.
str.format() ne zaman kullanılır?
str.format() aynı mini dili kullanır, ama değerleri metnin içinde değil, metoda argüman olarak alır. string modülü belgesine göre bu biçim dizesi sözdizimi f-string'lerle ilişkilidir, ancak daha sınırlıdır ve özellikle alanlarda keyfi ifadeleri desteklemez: Yalnızca argüman adı veya numarası, ardından .ozellik ve [indeks] erişimleri yazılabilir. Asıl avantajı, şablonun değerlerden önce ve ayrı tanımlanabilmesidir; örneğin bir ayar dosyasından okunan ya da tekrar tekrar kullanılan bir mesaj şablonunda f-string işe yaramaz, çünkü f-string yazıldığı anda hesaplanır.
sablon = 'Sayın {ad}, {tutar:.2f} TL ödemeniz alındı.'
print(sablon.format(ad='Ayşe', tutar=149.9))
# çıktı: Sayın Ayşe, 149.90 TL ödemeniz alındı.
print('{0} ve {1}, sonra yine {0}'.format('çay', 'simit'))
# çıktı: çay ve simit, sonra yine çay
veri = {'ad': 'Mert', 'sehir': 'Bursa'}
print('{ad}, {sehir} şubesinde'.format(**veri))
# çıktı: Mert, Bursa şubesinde
print('X: {0[0]}, Y: {0[1]}'.format((3, 5)))
# çıktı: X: 3, Y: 5Eski % biçimlendirmesi
C'deki printf'e benzeyen % operatörü hâlâ çalışır ve eski kodlarda sık görülür. Belgeler bu yöntemin, demetleri ve sözlükleri doğru gösterememek gibi yaygın hatalara yol açan bazı tuhaflıkları olduğunu söyler ve f-string, str.format() veya string.Template kullanmanın bu hatalardan kaçınmaya yardımcı olabileceğini belirtir. En bilinen tuzak, tek bir demeti yazdırmaya çalışmaktır:
print('%s: %d adet, %.2f TL' % ('Kalem', 3, 37.5)) # çıktı: Kalem: 3 adet, 37.50 TL
koordinat = (1, 2)
try:
print('Konum: %s' % koordinat)
except TypeError as e:
print(e)
# çıktı: not all arguments converted during string formatting (required 1, got 2)
print('Konum: %s' % (koordinat,)) # çıktı: Konum: (1, 2)
print(f'Konum: {koordinat}') # çıktı: Konum: (1, 2)Sorunun nedeni, % operatörünün sağdaki demeti tek bir değer olarak değil, değer listesi olarak yorumlamasıdır: Biçim dizesinde bir %s var ama demette iki eleman var. Python 3.15.2'nin mesajı bu sayıları da parantez içinde gösteriyor. Demeti tek elemanlı bir demetin içine koymak ya da f-string kullanmak sorunu çözer.
Tutorial ayrıca string.Template sınıfını anar: $ad biçiminde yer tutucular kullanan, çok daha az biçimlendirme denetimi sunan ama sözdizimi basit bir şablon yöntemidir.
t-string'ler: Python 3.14 ile gelen şablon literalleri
Python 3.14 (PEP 750) t önekiyle yazılan şablon literallerini ekledi. Sözdizimi f-string'lerle aynıdır, ama sonuç bir str değil, string.templatelib.Template nesnesidir. Bu nesne metnin sabit parçalarını ve değerleri birleşmeden önce ayrı ayrı tutar: strings sabit parçaların demetini, interpolations her ifade için bir Interpolation nesnesini, values ise değerlerin demetini verir. strings her zaman interpolations'dan bir eleman fazladır. Nesneyi dolaştığınızda sırayla boş olmayan metin parçalarını ve Interpolation'ları alırsınız.
ad = 'Ece'
sablon = t'Merhaba {ad}!'
print(type(sablon)) # çıktı: <class 'string.templatelib.Template'>
print(sablon.strings) # çıktı: ('Merhaba ', '!')
print(sablon.values) # çıktı: ('Ece',)
print(list(sablon)) # çıktı: ['Merhaba ', Interpolation('Ece', 'ad', None, ''), '!']
i = t'{3.14159:.2f}'.interpolations[0]
print(i.value, i.expression, i.conversion, i.format_spec) # çıktı: 3.14159 3.14159 None .2fEn önemli fark şudur: f-string'de dönüşüm ve biçim belirteci otomatik uygulanır, t-string'de ise yalnızca Interpolation nesnesine kaydedilir; onları uygulayıp uygulamamak şablonu işleyen koda kalmıştır. Belgeler, f-string dönüşüm kurallarını taklit etmek için string.templatelib.convert() yardımcısını sunar. Bu ayrım, kullanıcıdan gelen değerleri sabit metinden ayrı ele alabilmeyi sağlar; 3.14'ün yenilikler belgesi HTML ve SQL temizleme, güvenli kabuk komutları ve kayıt (logging) iyileştirmeleri gibi kullanım alanları sayar. Aşağıda yalnızca değerleri HTML kaçışına sokan küçük bir işleyici var:
import html
from string.templatelib import Interpolation, convert
def guvenli_html(sablon):
parcalar = []
for parca in sablon:
if isinstance(parca, Interpolation):
deger = format(convert(parca.value, parca.conversion), parca.format_spec)
parcalar.append(html.escape(deger))
else:
parcalar.append(parca) # sabit metin olduğu gibi kalır
return ''.join(parcalar)
yorum = '<script>alert(1)</script>'
puan = 4.666
print(guvenli_html(t'<p>{yorum}</p><b>{puan:.1f}</b>'))
# çıktı: <p><script>alert(1)</script></p><b>4.7</b>
print(f'<p>{yorum}</p>')
# çıktı: <p><script>alert(1)</script></p>Sabit <p> etiketleri korunurken kullanıcıdan gelen değer kaçışlandı; f-string ise iki parçayı ayırt edemediği için betiği olduğu gibi bıraktı. Belgelere göre bir Template ile düz bir str birleştirilemez, çünkü metnin sabit parça mı yoksa değer mi sayılacağı belirsizdir: t'a' + 'b' ifadesi Python 3.15.2'de TypeError: can only concatenate string.templatelib.Template (not "str") to string.templatelib.Template verir. İki şablonu ise + ile birleştirebilirsiniz.
Hangi yöntemi seçmeli?

| Yöntem | Sonuç | Ne zaman |
|---|---|---|
| f-string | str, yazıldığı anda hesaplanır | Günlük kullanımın büyük kısmı |
| str.format() | str, şablon önceden tanımlanabilir | Şablon ayrı tutuluyor veya tekrar kullanılıyorsa |
| % operatörü | str | Yalnızca eski kodla uyum gerektiğinde |
| string.Template | str, $ad yer tutucuları | Basit, kullanıcıların düzenleyeceği şablonlar |
| t-string (3.14+) | Template nesnesi | Değerleri sabit metinden ayrı işlemek (kaçışlama, güvenlik) |
Sık yapılan hatalar
- f önekini unutmak:
'{ad}'düz bir metindir, süslü parantezler olduğu gibi yazılır. - JSON veya CSS gibi süslü parantezli metinleri f-string'e koymak: Gerçek parantezleri
{{ve}}olarak ikileyin. - Tipe uymayan belirteç kullanmak: Metne
:dveya:.2fuygulamakValueErrorverir; önce sayıya çevirin. - Genişliğin uzun değeri keseceğini sanmak: Genişlik en küçük boyuttur; kesmek için metinlerde hassasiyet (
:.10) kullanın. - Lambda veya := ifadesini parantezsiz yazmak: İki nokta biçim belirteci sanılır; ifadeyi parantez içine alın.
- f-string'i docstring olarak kullanmak: İçinde ifade olmasa bile
__doc__Noneolur. - Şablonu önceden tanımlamak için f-string kullanmak: f-string hemen hesaplanır; sonradan doldurulacak şablon için
str.format()kullanın.
Sık Sorulan Sorular
f-string içinde ondalık basamak sayısını nasıl sınırlarım?
Biçim belirtecinde hassasiyet verin: f'{sayi:.2f}' iki basamak gösterir. Binlik ayırıcı için f'{sayi:,.2f}' yazın.
f-string ile str.format() arasındaki fark nedir?
İkisi aynı biçim mini dilini kullanır. f-string içine doğrudan ifade yazarsınız ve metin yazıldığı yerde hesaplanır; str.format() ise değerleri argüman olarak alır, bu yüzden şablonu önceden tanımlayıp sonra doldurabilirsiniz.
Değişkenin adını ve değerini birlikte nasıl yazdırırım?
= belirtecini kullanın: f'{x=}' çıktısı x=5 gibidir. Boşluklar korunur, metinler tırnaklı gösterilir.
t-string, f-string'in yerini mi alıyor?
Hayır. t-string bir metin değil, işlenmesi gereken bir Template nesnesi üretir. Doğrudan metin istediğiniz durumlarda f-string kullanmaya devam edersiniz; t-string, değerleri ayrıca işlemek istediğiniz kütüphane ve şablon kodları içindir.
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 · String metotları · Sayılar: int, float, decimal · datetime ile tarih ve saat · logging modülü · Unicode ve Türkçe karakter · Python 3.15 yenilikleri