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.
| İfade | Sonuç | Not |
|---|---|---|
int("42"), int(" 42 ") | 42 | Baştaki/sondaki boşluk sorun değil |
int("1_000") | 1000 | Alt çizgi basamak ayırıcısı kabul edilir |
int("4.5") | ValueError | Ondalık metni doğrudan int olmaz: int(float("4.5")) |
int(4.9), int(-4.9) | 4, -4 | Yuvarlamaz, sıfıra doğru keser |
int("ff", 16) | 255 | İkinci parametre taban |
float("12.5"), float("1e3") | 12.5, 1000.0 | Bilimsel gösterim kabul |
float("12,5") | ValueError | Python ondalık ayırıcı olarak yalnız nokta bilir |
float("nan"), float("inf") | nan, inf | Sürpriz: bunlar da geçerli float! |
bool("False"), bool("0") | True, True | Boş olmayan her metin True |
bool("") | False | Yalnı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() 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))
"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:
| Metin | isdecimal() | isdigit() | isnumeric() | int() çalışır mı? |
|---|---|---|---|---|
"123" | True | True | True | Evet |
"٣" (Arapça 3) | True | True | True | Evet → 3 |
"²" (üst simge) | False | True | True | Hayır! |
"½", "Ⅻ" | False | False | True | Hayır |
"-5", "3.5", " 7", "" | False | False | False | -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.")
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")
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.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).