Ana içeriğe geç
Kesit Python
Temel · Akış kontrolü

Kullanıcı girdisi ve tür dönüşümü

input() her zaman str döndürür: int/float/bool dönüşümlerinin tuzaklarını, Türkçe virgüllü ondalığı, isdigit/isnumeric/isdecimal farkını, while True + try/except doğrulama döngüsünü, split ile çoklu değer ve varsayılan değer kalıplarını öğrenirsin.

Uygulamada aç, 18 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Kullanıcı ne yazarsa yazar

Anadolu Market'in depo görevlisi stok sayım programına "12" yerine "on iki", "12,5" ya da yanlışlıkla boş bir satır girer. Kasa görevlisi "Onaylıyor musun?" sorusuna "Hayır" yazar ve program bunu "evet" sanar. Kullanıcı girdisi (user input) programın en kirli kapısıdır: her şey metin olarak gelir, hiçbir şeyin doğru biçimde geleceği garanti değildir. İlk program dersinde input() ile tanıştın, değişkenler dersinde int() ve float() gördün. Bu derste ikisini birleştirip sağlam bir girdi katmanı kuracaksın: dönüştür, doğrula, gerekirse tekrar sor.

input() her zaman str döndürür

input(istem) ekrana istem (prompt) metnini yazar, kullanıcının Enter'a basmasını bekler ve yazılanı sondaki satır sonu olmadan bir str olarak döndürür. Kullanıcı 42 yazsa da gelen değer "42" metnidir.

adet = input("Adet: ")          # kullanıcı 3 yazar
fiyat = input("Fiyat: ")        # kullanıcı 20 yazar
print(adet * 2)                 # 33   (metin tekrarı!)
print(adet + fiyat)             # 320  (metin birleştirme!)
print(int(adet) * int(fiyat))   # 60

Bu derste tarayıcıdaki örnekler input() yerine "kullanıcının yazdığı" metni doğrudan bir değişkene koyarak çalışır; alıştırmalarda ise gerçek input() kullanacaksın ve sistem senin yerine yazacak. Doğrulayıcı istemi ve girilen değeri çıktıya ekler: Ad: Ayşe gibi.

girilen_adet = "3"        # input("Adet: ") sonucu gibi düşün
girilen_fiyat = "20"
print(type(girilen_adet).__name__)
print(girilen_adet * 2, girilen_adet + girilen_fiyat)
print(int(girilen_adet) * int(girilen_fiyat))

Dönüşüm fonksiyonları ve tuzakları

int(), float(), bool() ve str() yeni bir değer üretir; orijinal metin değişmez. Hangi metinleri kabul ettiklerini bilmek, ValueError'ı önceden kestirmeni sağlar.

İfadeSonuçNot
int("42"), int(" 42 ")42Baştaki/sondaki boşluk sorun değil
int("1_000")1000Alt çizgi basamak ayırıcısı kabul edilir
int("4.5")ValueErrorOndalık metni doğrudan int olmaz: int(float("4.5"))
int(4.9), int(-4.9)4, -4Yuvarlamaz, sıfıra doğru keser
int("ff", 16)255İkinci parametre taban
float("12.5"), float("1e3")12.5, 1000.0Bilimsel gösterim kabul
float("12,5")ValueErrorPython ondalık ayırıcı olarak yalnız nokta bilir
float("nan"), float("inf")nan, infSürpriz: bunlar da geçerli float!
bool("False"), bool("0")True, TrueBoş olmayan her metin True
bool("")FalseYalnız boş metin False
str(3.0)"3.0"Sayıdan metne her zaman çalışır
for metin in ["42", " 42 ", "1_000", "4.5", "on iki", ""]:
    try:
        print(repr(metin), "->", int(metin))
    except ValueError as e:
        print(repr(metin), "-> ValueError:", e)

print(bool("False"), bool("0"), bool(""), bool(" "))
print(int(float("4.5")), round(float("4.5")), round(float("5.5")))
bool("False") True'durbool() metnin içeriğine bakmaz, yalnızca boş olup olmadığına bakar. Kullanıcıdan evet/hayır almak için metni kendin yorumlamalısın: cevap.strip().lower() in ("e", "evet"). Aynı tuzak ortam değişkenlerinde ve CSV'deki "True"/"False" sütunlarında da karşına çıkar.

Son satırdaki round(4.5) sonucunun 4 çıkması hata değil: Python "bankacı yuvarlaması" yapar (yarımları çift sayıya). Sayılar dersinde bunu ayrıntılı gördün.

Virgüllü ondalık: "12,5" → 12.5

Türkiye'de ondalık ayırıcı virgül, binlik ayırıcı noktadır: 1.234,56. Python ise tam tersini bekler. Kullanıcı ve Excel verisinde bu biçim çok sık gelir. Güvenli dönüşüm sırası: önce binlik noktalarını sil, sonra virgülü noktaya çevir.

def tr_float(metin):
    temiz = metin.strip().replace(" ", "")
    if "," in temiz:                       # Türkçe biçim: 1.234,56
        temiz = temiz.replace(".", "").replace(",", ".")
    return float(temiz)

for m in ["12,5", "1.234,56", " 99 ", "3.75", "1 250,00"]:
    print(repr(m), "->", tr_float(m))
Belirsiz durum"1.234" bin iki yüz otuz dört mü, bir virgül iki yüz otuz dört mü? Metinden anlaşılamaz. Bu yüzden kurumsal sistemlerde girdi biçimi açıkça belirlenir ("ondalık için virgül kullanın") ya da her iki ayırıcıyı içeren metin reddedilip kullanıcıya tekrar sorulur. Para için float yerine Decimal kullanmayı da unutma.

isdigit, isnumeric, isdecimal farkı

Bir metnin sayı olup olmadığını dönüştürmeden önce sormak için üç metot vardır. Hepsi boş metinde, eksi işaretinde, noktada ve boşlukta False döner. Farkları Unicode'daki özel rakamlardadır:

Metinisdecimal()isdigit()isnumeric()int() çalışır mı?
"123"TrueTrueTrueEvet
"٣" (Arapça 3)TrueTrueTrueEvet → 3
"²" (üst simge)FalseTrueTrueHayır!
"½", "Ⅻ"FalseFalseTrueHayır
"-5", "3.5", " 7", ""FalseFalseFalse-5 ve " 7" evet!

Kural: int() öncesi ön kontrol için en güvenlisi isdecimal()'dır. Ama tablo son satırı gösteriyor ki hiçbiri negatif sayıyı ve boşluklu girdiyi tanımaz. Bu yüzden profesyonel kod "önce sor" yerine "dene ve yakala" (EAFP: easier to ask forgiveness than permission) yaklaşımını tercih eder: try: int(metin) except ValueError: ....

for m in ["123", "²", "½", "-5", " 7"]:
    try:
        sonuc = int(m)
    except ValueError:
        sonuc = "dönüştürülemez"
    print(f"{m!r:6} isdecimal={m.isdecimal()!s:5} isdigit={m.isdigit()!s:5} int: {sonuc}")

Doğrulama döngüsü: doğru girene kadar sor

Kullanıcıya bir kez sorup hatalı girdide programı çökertmek kabul edilemez. Standart kalıp: while True ile sonsuz döngü kur, try içinde dönüştür, aralık gibi iş kurallarını kontrol et, her şey yolundaysa break ile çık. Hata mesajı neyin yanlış olduğunu ve ne beklendiğini söylemeli.

while True:
    metin = input("Adet (1-99): ")
    try:
        adet = int(metin)
    except ValueError:
        print("Lütfen tam sayı gir.")
        continue
    if 1 <= adet <= 99:
        break
    print("1 ile 99 arasında olmalı.")
print("Sepete", adet, "adet eklendi.")

Tarayıcıda aynı mantığı, kullanıcının sırayla yazdığı değerleri bir listeden alarak çalıştırabilirsin:

girdiler = iter(["on iki", "0", "150", "12"])   # kullanıcının sırayla yazdıkları

def sor(istem):
    deger = next(girdiler)
    print(istem + deger)
    return deger

while True:
    metin = sor("Adet (1-99): ")
    try:
        adet = int(metin)
    except ValueError:
        print("Lütfen tam sayı gir.")
        continue
    if 1 <= adet <= 99:
        break
    print("1 ile 99 arasında olmalı.")
print("Sepete", adet, "adet eklendi.")
Deneme hakkı sınırı koyOtomatik testlerde ya da boru hattında (stdin bir dosyadan gelirken) sonsuz döngü programı kilitleyebilir. for deneme in range(3): ile hak sınırı koyup döngü sonunda else: bloğunda "çok fazla hatalı deneme" diyerek çıkmak daha sağlamdır. Girdi bittiğinde input() EOFError fırlatır; onu da yakalayabilirsin.

Bir satırda birden fazla değer

Kullanıcı "1,75 70" ya da "120 85 140" gibi birden fazla değeri tek satıra yazabilir. split() argümansız çağrılınca her türlü boşlukta böler ve fazla boşlukları yok sayar; ardından her parçayı dönüştürürsün.

satir = "  120   85 140 "               # input("Satışlar: ") sonucu gibi
sayilar = [int(p) for p in satir.split()]
print(sayilar, sum(sayilar))

en, boy = map(int, "40x60".split("x"))   # tam iki parça bekler
print(en * boy, "cm²")

try:
    a, b = "1 2 3".split()
except ValueError as e:
    print("Beklenenden fazla değer:", e)

Açma (unpacking) ile a, b = ... yazdığında parça sayısı tutmazsa ValueError alırsın; bu da bir doğrulama fırsatıdır.

Varsayılan değer: Enter'a basılırsa

Komut satırı araçlarında yaygın bir kibarlık: köşeli parantezde varsayılanı gösterip boş bırakılırsa onu kullanmak. or operatörü boş metni yanlış saydığı için tek satırda çözülür.

girilen_sehir = ""          # kullanıcı yalnız Enter'a bastı
girilen_gun = " 30 "
sehir = girilen_sehir.strip() or "İstanbul"
gun = int(girilen_gun.strip() or "7")
print(f"Rapor: {sehir}, {gun} gün")
Gerçek işteIlgaz Bank şubelerinde kullanılan eski bir terminal uygulaması, gişe görevlisinin girdiği tutarı float(input()) ile okuyordu. "1.500" yazan görevli 1,5 TL'lik işlem yaptı; "1500,00" yazan ise ValueError ile ekranı kilitledi. Yeni sürümde girdi katmanı üç kurala bağlandı: Türkçe biçim ayrıştırıcı (binlik nokta, ondalık virgül), aralık kontrolü (0 < tutar ≤ günlük limit) ve büyük tutarlarda "1.500,00 TL onaylıyor musunuz? (e/h)" teyidi. Aynı ilkeler web formlarında da geçerlidir: istemci tarafı kontrol yetmez, sunucu girdiyi her zaman yeniden doğrular.
Uzmanlaş

Asla eval(input()) yazma

Eski öğreticilerde "sayı ya da liste girsin diye" eval(input()) görürsün. eval metni Python kodu olarak çalıştırır; kullanıcı __import__("os").remove("veri.db") yazarsa onu da çalıştırır. Bir metni Python değerine (sayı, liste, sözlük) güvenle çevirmek için ast.literal_eval kullan; yalnız sabit değerleri kabul eder. JSON biçimindeki girdiler için json.loads daha da uygundur.

Girdi katmanını ayır

İş mantığını input() çağrılarıyla karıştırma. "Metni al → dönüştür → doğrula" işini saf fonksiyonlara (tr_float, evet_mi, adet_dogrula) koy; input() yalnızca en dış katmanda kalsın. Böylece aynı fonksiyonları komut satırında, web formunda ve CSV içe aktarmada yeniden kullanır, input olmadan test edersin.

Etkileşimsiz girdi: stdin

Sunucuda çalışan betiklerin karşısında insan yoktur; girdi bir dosyadan ya da başka programdan boru ile gelir (python sayim.py < sayim.txt). Bu durumda input() her satırı okur ve dosya bitince EOFError fırlatır. Satır satır işlemek için for satir in sys.stdin: kalıbı daha uygundur. Terminal dersinde stdin'i ve yönlendirmeyi görmüştün.

Parola girişi

Parola gibi gizli bilgiler input() ile alınmaz; ekranda görünür. Standart kütüphanedeki getpass.getpass("Parola: ") yazılanı göstermez (kendi terminalinde dene).

Alıştırmalara geç (18)