Ders 05 / 18
Tip Dönüşümü
Açık ve örtük dönüşüm, kayıplı daraltma, dönüşüm hataları ve girdi doğrulama.
İçindekiler
Önceki ders, aynı işlecin farklı tiplerde farklı anlam taşıdığını gösterdi. Geriye bir soru kaldı: bir ifadede farklı tipler yan yana geldiğinde ne olur?
Yanıt üç seçenekten biridir: dil dönüşümü kendiliğinden yapar, programcının açıkça istemesini bekler, ya da işlemi reddeder. Bu dersin konusu bu üç davranış ve dönüşümlerin bedelidir.
Açık Dönüşüm
Açık dönüşümde programcı, hedef tipi belirterek dönüşümü ister:
print(int("12") + 1) # 13 — dizgiden tam sayıya print(float("3.5") * 2) # 7.0 — dizgiden gerçel sayıya print(str(12) + "1") # 121 — tam sayıdan dizgiye print(int(3.9)) # 3 — gerçel sayıdan tam sayıya
Açık dönüşümün üstünlüğü görünür olmasıdır: kodu okuyan, dönüşümün burada yapıldığını ve hangi yöne gittiğini bilir.
Dördüncü satır dikkat ister. Gerçel sayıdan tam sayıya dönüşüm yuvarlamaz, keser: kesir kısmı atılır.
print(int(3.9), int(-3.9)) # 3 -3 — sıfıra doğru kesme print(round(3.9)) # 4 — yuvarlama ayrı bir işlemdir print(round(2.5), round(3.5)) # 2 4 — yarımlar en yakın çift sayıya
Son satır, sayısal kodda bilinmesi gereken bir ayrıntıdır: yarım değerlerin hep yukarı yuvarlanması evrensel değildir. Yaygın bir kural, yarımları en yakın çift sayıya yuvarlamaktır; bu, çok sayıda yuvarlamanın toplamda yukarı kaymasını engeller.
Örtük Dönüşüm
Örtük dönüşümde dil, tipleri uyumlu hâle getirmek için kendiliğinden dönüşüm yapar:
print(3 + 2.5) # 5.5 — tam sayı, gerçel sayıya yükseltildi print(type(3 + 2.5)) # <class 'float'>
Buradaki dönüşüm genişletmedir: tam sayı, gerçel sayı kümesinde temsil edilebilir. Genişletme yönündeki örtük dönüşümler genellikle güvenlidir.
Diller, örtük dönüşüme ne kadar izin verdiklerine göre ayrışır. Kimi diller yalnızca
güvenli genişletmelere izin verir; kimileri neredeyse her tipi birbirine çevirir. İkinci
grupta "3" + 4 gibi bir ifade hata vermez, sessizce bir sonuç üretir — ve bu sonucun ne
olduğu dile göre değişir. Kolaylık, hatanın sessizleşmesi pahasına gelir.
Python bu iki uçtan ilkine yakındır: sayılar arasında yükseltme yapar, ancak dizgi ile sayıyı toplamayı reddeder ve hata verir.
Kayıplı Dönüşüm
Bazı dönüşümler bilgi kaybeder. Üç tipik durum:
Kesir kaybı. Gerçel sayıdan tam sayıya geçişte kesir kısmı atılır; geri dönüş, eski değeri vermez.
Aralık taşması. Geniş bir tam sayı, dar bir tipe sığmayabilir. Sabit genişlikli dillerde sonuç sarar; önceki kursun taşma dersinde bunun neden sessizce olduğu görülmüştü.
Kesinlik kaybı. Büyük tam sayılar, gerçel sayı gösteriminin mantis genişliğini aşabilir:
buyuk = 10 ** 23 print(float(buyuk) == buyuk) # False print(int(float(buyuk))) # 99999999999999991611392
Değer sessizce değişmiştir; hata iletisi yoktur. Kayan noktalı sayılar dersinde belirtilen sınır burada gözlenir hâle gelir.
Pratik kural: daraltma yönündeki dönüşümler açıkça yazılır ve gerekçesi bilinir. Örtük daraltmaya izin veren dillerde derleyici uyarıları açık tutulur.
Dönüşüm Hataları
Dönüşüm her zaman mümkün değildir. Dizgi bir sayıyı temsil etmiyorsa dönüşüm hata verir:
# int("üç") -> çalışma zamanı hatası: geçersiz sayı gösterimi # int("3.5") -> çalışma zamanı hatası: tam sayı gösterimi değil print(int(float("3.5"))) # 3 — iki adımda: önce gerçel, sonra kesme
Bu, dış dünyadan gelen veriyle çalışırken kuraldır: kullanıcı girdisi, dosya içeriği ve ağ yanıtı doğrulanmadan dönüştürülmez. İki yaygın kalıp vardır.
Birincisi, dönüşümü denemek ve hatayı yakalamak:
def sayiya_cevir(metin: str, varsayilan: int = 0) -> int: """Metni tam sayıya çevirir; çevrilemiyorsa varsayılanı döndürür.""" try: return int(metin) except ValueError: return varsayilan print(sayiya_cevir("12")) # 12 print(sayiya_cevir("üç")) # 0 print(sayiya_cevir("üç", -1)) # -1
İkincisi, dönüştürmeden önce biçimi sınamak:
metin = "12" if metin.isdigit(): olcum = int(metin) print(olcum + 1) # 13
İki kalıptan hangisinin seçileceği, hatanın beklenen bir durum mu yoksa istisnai bir durum mu olduğuna bağlıdır. Kullanıcı girdisinde geçersiz değer beklenen bir durumdur; programın kendi ürettiği verinin geçersiz olması ise istisnaidir.
Girdiden Sayıya: Tam Örnek
Dış girdinin dizgi olarak gelmesi ve sayısal işlem için dönüştürülmesi gereği, bu konunun tüm parçalarını bir araya getirir. Kursun ortak problemi üzerinden:
# Girdi: her satırda bir ölçüm bulunan metin (dosyadan okunmuş gibi düşünün) ham_girdi = ["12", "18", "7", "yirmi", "25", ""] olcumler = [] atlanan = 0 for satir in ham_girdi: metin = satir.strip() # baştaki ve sondaki boşlukları at try: olcumler.append(int(metin)) # geçerliyse sayıya çevir ve ekle except ValueError: atlanan += 1 # değilse say ve geç print(olcumler) # [12, 18, 7, 25] print(atlanan) # 2 print(sum(olcumler) / len(olcumler)) # 15.5 print(max(olcumler)) # 25
Program üç ayrı karar içerir ve üçü de bu konuda kurulan kavramlara dayanır: girdi temizlenir (dizgi işlemi), dönüştürülür (açık dönüşüm) ve geçersiz değerler ayrı sayılır (hata yakalama).
Dördüncü bir karar da vardır ve gözden kaçmaya elverişlidir: geçersiz satırların atlanması mı, programın durdurulması mı, yoksa varsayılan bir değerle doldurulması mı gerekir? Bu, dilin değil problemin sorusudur. Ölçüm verisinde eksik değerin nasıl ele alınacağı, veri analizi müfredatının ayrı bir konusudur.
for döngüsünün nasıl çalıştığı sonraki konunun konusudur; burada yalnızca her satırın
sırayla işlendiği kadarıyla okunması yeterlidir.
Sessiz Tuzak: Sayı Gibi Görünen Dizgiler
Sayısal görünen bir değerin dizgi olarak kalması, hata vermeyen ama yanlış sonuç veren bir duruma yol açar:
print("12" < "9") # True — dizgi karşılaştırması: karakter karakter print(12 < 9) # False — sayısal karşılaştırma print(sorted(["12", "9", "100"])) # ['100', '12', '9'] print(sorted([12, 9, 100])) # [9, 12, 100]
Aynı sınıfın ikinci örneği, sayıların yazımının bölgeye göre değişmesidir. Ondalık ayracı kimi yazımda nokta, kimi yazımda virgüldür; binlik ayracı da benzer biçimde değişir. Bir dilin standart dönüşüm işlevi genellikle tek bir yazımı kabul eder; kullanıcıdan veya dış kaynaktan gelen metin bu yazıma uymuyorsa dönüşüm başarısız olur ya da — daha kötüsü — sayının yalnızca bir bölümünü okur. Bu yüzden dış verinin hangi yazımla geldiği bilinmeli, dönüşüm o yazıma göre yapılmalıdır.
Dizgiler karakter karakter karşılaştırılır; "1" karakteri "9" karakterinden önce
gelir. Dosyadan okunan ölçümler dönüştürülmeden sıralanırsa, sonuç sayısal sıra değil
sözlük sırası olur. Bu, birinci dersteki mantık hatası sınıfının tipik örneğidir:
program çalışır, hata vermez, yanlış sonuç verir.
Özet
- Açık dönüşümde hedef tip programcı tarafından belirtilir; örtük dönüşümü dil kendiliğinden yapar.
- Gerçel sayıdan tam sayıya dönüşüm yuvarlamaz, keser; yuvarlama ayrı bir işlemdir ve yarım değerlerin kuralı diller arasında değişebilir.
- Genişletme yönündeki dönüşümler güvenlidir; daraltma yönündekiler kesir, aralık veya kesinlik kaybedebilir ve bu kayıp sessizdir.
- Dizgiden sayıya dönüşüm başarısız olabilir; dış girdi doğrulanmadan dönüştürülmez.
- Sayı gibi görünen dizgiler karakter karakter karşılaştırılır ve sıralama sonucunu değiştirir.
Sonraki Adım
Bu konu, değerleri ve onlardan ifade kurmayı tamamladı. Ancak programlar yalnızca yukarıdan aşağı akmaz: koşula göre dallanır ve tekrar eder. Sonraki konu, akışı yönlendiren yapıları — koşullu dallanma ve döngüleri — ele alacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.