Koşullar, döngüler ve string işlemleri

C’de kullandığınız if yapısını ve döngüleri bu hafta Python’da yazacağız. Bu kavramları baştan anlatmayacağız. Python’ın daha sade yazımına ve bir listenin ya da metnin elemanlarını sayaç tutmadan sırayla dolaşmasına bakacağız.

Bu bölümün kapsamı

NoteSınavda sorulur
  • if / elif / else zincirinde sınır değerinin hangi dala düştüğü
  • Bir listenin ya da metnin elemanları üzerinde doğrudan dolaşma; enumerate() ve zip()
  • range() bitişinin dışarıda kalması ve adım parametresi
  • while döngüsünde koşuldaki değeri değiştiren adım
  • break ile continue farkı
  • String’in değiştirilemez olması
  • strip(), split() ve join() ile bir metin kaydını parçalara ayırma ve birleştirme
  • lower() / upper() dönüşümünün Türkçe I / İ sınırı
  • Unicode normalleştirme biçimleri ve yerel ayar (locale) kütüphaneleri
  • Düzenli ifadeler
  • Liste kavraması

Bu başlıklar konunun devamıdır; ileride karşınıza çıkar ama bu derste ezberlemeniz beklenmiyor.

Döngüyü sayaçla mı, değerle mi kurmalıyım?

C’de bir diziyi dolaşırken ilk aklınıza gelen, bir indeks değişkeni tutmaktır. Python’da ise çoğu zaman değerlerin kendisini sırayla alırız. Kod kısalır, ne yapmak istediğimiz de daha kolay okunur. İndeks gerçekten gerektiğinde enumerate() ve zip() var. Bölümün ikinci yarısında aynı soruyu metinler için soracağız.

if: parantez ve süslü parantez yok

Python’da koşulun sonuna : gelir; blok girintiyle belirlenir. else if yerine elif kullanılır.

Sınır değerini düşünün

score = 70 için sonuç ne olur? 69 için ne olur? Koşul zincirlerinde sınır değerlerini ayrıca test edin; doğru görünen koddaki gizli hatalar böyle yakalanır.

for: sayaç tutmadan dolaşmak

C’de bir string’i dolaşmak için indeks değişkeni kullanmaya alışmış olabilirsiniz. Python’da çoğu zaman elemana doğrudan erişebiliriz:

İndeksle dolaşma ile bir dizinin değerlerini for döngüsüyle doğrudan dolaşmayı karşılaştıran diyagram.

Değer üzerinde doğrudan dolaşma

Bu kodda letter, her turda sıradaki karakteri alır. İndeks gerekmediği için ayrıca sayaç tutmuyoruz.

İndeks gerçekten gerekiyorsa range() kullanılabilir; fakat Python’da hem indeks hem değer gerektiğinde çoğu zaman enumerate() daha kısa bir yoldur:

Böylece range(len(word)) yazıp her turda word[i] ile elemana erişmek zorunda kalmazsınız.

İki diziyi aynı anda dolaşmak istediğimizde zip() kullanılabilir:

zip(), verilen listelerden en kısası bitince durur. Uzunlukların eşit olması gerekiyorsa bunu ayrıca kontrol etmelisiniz.

range() son değeri içermez

range fonksiyonunda bitiş değerinin aralığa dâhil edilmediğini gösteren sınır diyagramı.

range() sınırı

range(5) → 0, 1, 2, 3, 4. Son sınırın dışarıda kalması, C’deki i < 5 kalıbına benzer.

range(start, stop, step) biçimindeki üçüncü parametre adım değeridir. Geriye saymak için negatif adım kullanılır:

for number in range(10, 0, -1):
    print(number)

Adımın yönü başlangıçtan bitişe giden yönle uyuşmazsa aralık boş kalır. Emin değilseniz küçük bir list(range(...)) denemesiyle bakın.

while: koşula bağlı tekrar

Tekrar sayısı baştan belli değilse while daha doğal olabilir:

while kullanırken üç soruyu sorun:

  1. Döngü başlarken koşuldaki değişkenlerin değeri ne?
  2. Her turda hangi değer değişiyor?
  3. Bu değişiklikle döngüyü bitirecek koşul gerçekten oluşabilir mi?

Bu sorulardan birinin cevabı belli değilse döngü sonsuza kadar dönebilir.

break ve continue

break, içinde bulunduğu en yakın döngüyü hemen bitirir. continue ise o turun kalanını atlayıp sonraki tura geçer:

Bu örnekte -1, verinin bittiğini bildiren bir işaret değeri (sentinel) gibi döngüyü bitirir. C’de “-1 girilene kadar oku” diye yazdığınız döngüler bu kalıptır. 0 ise yazdırılmadan atlanır. break ve continue’yu her yerde kullanmayın; kodun amacını daha açık gösterdikleri yerde işe yararlar.

String bir karakter dizisidir

Bir string’in tek bir karakterine indeksle (text[0]), bir parçasına dilimleyerek (text[:5]) erişebilirsiniz. String’lerin bir de hazır metotları vardır: text.strip() gibi, değerin arkasına nokta koyup çağırdığınız fonksiyonlar.

String değiştirilemez (immutable): oluşturulduktan sonra içindeki karakterler değişmez. text.upper() var olan string’i değiştirmez, yeni bir string döndürür.

Değiştirilebilir ile değiştirilemez arasındaki bu fark gelecek hafta önem kazanacak. Listeleri ve iki adın aynı nesneyi gösterdiği durumları o zaman göreceğiz.

Sık kullanılan string araçları

Araç Amaç Örnek
strip() baş/son boşlukları temizler " a ".strip()
split(sep) metni parçalara ayırır "Ada,80".split(",")
sep.join(parts) parçaları birleştirir ", ".join(names)
replace(a, b) a geçen her yere b koyar text.replace("-", " ")
startswith(prefix) metnin verilen parçayla başlayıp başlamadığına bakar name.startswith("A")
in bir parçanın metinde geçip geçmediğine bakar "py" in "python"

5. haftada dosyadaki satırları parçalarken split() ve strip()’i sık kullanacağız.

Türkçede büyük/küçük harf dönüşümüne dikkat (sınav dışı)

Python’ın lower() / upper() dönüşümleri Unicode kurallarına göre çalışır; Türkçeye özgü yerel ayar (locale) kurallarını uygulamaz. Bu yüzden özellikle I/ı ve İ/i çiftlerinde Türkçede beklediğiniz sonucu vermeyebilir:

Türkçe metinleri büyük/küçük harf ayrımı yapmadan karşılaştırırken lower() çağrısının her durumu çözdüğünü varsaymayın. Bu derste Türkçeye özgü kuralların ayrıntısına girmeyeceğiz; yalnızca böyle bir sorunun var olduğunu bilmenizi istiyoruz.

Alıştırma: Koşulu tamamla

Bir kullanıcı adı en az 5 karakter olmalı ve boşluk içermemelidir.

len(username) >= 5 ile " " not in username ifadelerini and ile birleştirebilirsiniz.

valid = len(username) >= 5 and " " not in username

Alıştırma: Doğrudan dolaşarak sayma

Aşağıdaki kod bir metindeki a harflerini sayıyor. Önce sonucu tahmin edin.

Burada ayrıca bir indeks sayacı tutmuyoruz; karakterler üzerinde doğrudan dolaşıyoruz. Ardından kodu, büyük ve küçük harfi ayırmadan sayacak biçimde değiştirin. Örneğin "Ankara" için hem A hem a sayılmalıdır. Sonra "Iğdır" ve "İzmir" gibi Türkçe örneklerde lower() ne yapıyor, bakın. Bu yöntemin her Türkçe metinde neden doğru sonuç vermediğini açıklayın.

Alıştırma: Off-by-one hatasını düzelt

Aşağıdaki program 1’den 10’a kadar sayıların toplamını hesaplamalı; ancak sonuç eksik çıkıyor.

Neden 10 işlenmiyor? Yalnızca gerekli tek değeri değiştirerek düzeltin.

Alıştırma: while döngüsünü güvenli hâle getir

Bu kodu çalıştırın. Sonra break satırını kaldırırsanız ne olacağını çalıştırmadan önce açıklayın. Web sürümünde sonsuz döngüyü gerçekten çalıştırmak yerine mantığını tartışmak yeterlidir.

Sıra sizde: Metin özeti

Bir metnin aşağıdaki bilgilerini yazdıran bir program yazın:

  • Toplam karakter sayısı,
  • Boşluk sayısı,
  • Sesli harf sayısı,
  • split() ile kelime sayısı,
  • Metnin başındaki ve sonundaki boşluklar strip() ile temizlendikten sonra ilk ve son karakter.

Örnek metni değişken olarak verin; input() zorunlu değildir. Programda en az bir for, bir if, bir enumerate() ya da zip() ve iki farklı string metodu bulunsun.

Warning

Temizlenmiş metin boşsa text[0] veya text[-1] yazmak IndexError verir. Yalnızca boşluklardan oluşan bir metin de strip() sonrasında boş kalır. İlk ve son karaktere erişmeden önce metnin boş olup olmadığını kontrol edin.

Çalışır kod görevi: Programınızı en az normal metin, boş string ve yalnızca boşluklardan oluşan metinle çalıştırın. Üçünde de programın hata vermeden bitip beklenen sonucu yazdığını gösterin.

C’den Python’a düşünme farkı

Aşağıdaki iki döngü aynı işi yapar:

# İndeks temelli
for i in range(len(text)):
    print(text[i])

# Değer temelli
for ch in text:
    print(ch)

İndekse ihtiyacınız yoksa ikinci döngü ne yapmak istediğinizi daha açık gösterir. Hem indeks hem değer gerekiyorsa üçüncü bir yol var: enumerate(text). Python öğrenirken C kodunu satır satır Python’a çevirmek yerine, o işin Python’da nasıl yazıldığını öğrenmeye çalışın.

Sınav provası

Önce kendi cevabınızı seçin; sonra cevap anahtarında her şıkkın neden doğru veya yanlış olduğunu okuyun. Çeldiriciler uydurma değil, bu konuda gerçekten yapılan hatalardır. Sınav maddeleri de bu mantıkla yazılır.

Madde 1. Aşağıdaki program score = 70 iken ne yazdırır?

if score >= 85:
    result = "AA"
elif score >= 70:
    result = "BB"
else:
    result = "Başarısız"

print(result)
  • A. BB
  • B. Hiçbir şey yazmaz
  • C. BB ve Başarısız
  • D. Başarısız
  • E. AA

Madde 2. Aşağıdaki iki yazım score = 90 için neden farklı sonuç verir?

# A
if score >= 50:
    durum = "Geçti"
if score >= 85:
    durum = "Yüksek"

# B
if score >= 50:
    durum = "Geçti"
elif score >= 85:
    durum = "Yüksek"
  • A. B söz dizimi hatası verir; elif daha dar bir koşulla kullanılamaz
  • B. İkisi de Yüksek verir; elif yalnızca yazım kısaltmasıdır
  • C. Fark yalnızca score 50’nin altındayken görülür
  • D. İkisi de Geçti verir
  • E. A Yüksek, B Geçti verir; B’de elif hiç sınanmaz

Madde 3. Aşağıdaki program ne yazdırır?

word = "abc"
for letter in word:
    print(letter)
  • A. Alt alta 0, 1, 2
  • B. abc
  • C. Hata verir; string üzerinde doğrudan dolaşılamaz
  • D. Alt alta a, b, c
  • E. Alt alta a b, b c, c

Madde 4. Hem indeks hem değer gerektiğinde en doğrudan yazım hangisidir?

  • A. for i in range(len(word)): ve gövdede word[i]
  • B. for index, letter in zip(word):
  • C. for index in word:
  • D. for letter in word.index():
  • E. for index, letter in enumerate(word):

Madde 5. list(range(2, 7)) ne verir?

  • A. [3, 4, 5, 6, 7]
  • B. [2, 3, 4, 5, 6]
  • C. [0, 1, 2, 3, 4, 5, 6]
  • D. [2, 3, 4, 5, 6, 7]
  • E. [2, 7]

Madde 6. Aşağıdaki program 1’den 10’a kadar sayıların toplamını yazdırmalı ama 45 yazıyor. Hangi düzeltme doğrudur?

total = 0
for number in range(1, 10):
    total += number
print(total)
  • A. range(1, 11) yazılmalıdır
  • B. range(0, 10) yazılmalıdır
  • C. for yerine while kullanılmalıdır
  • D. total = 1 ile başlanmalıdır
  • E. total += number + 1 yazılmalıdır

Madde 7. Aşağıdaki döngü neden hiç bitmez?

attempts = 0
password = "1234"
guess = "0000"

while guess != password:
    attempts += 1
    print("Yanlış deneme:", attempts)
  • A. print() çağrısı döngüyü yavaşlattığı için
  • B. attempts += 1 satırı koşulu sıfırladığı için
  • C. Koşuldaki guess döngü içinde hiç değişmez
  • D. while döngüleri Python’da break olmadan bitemez
  • E. != operatörü stringlerde çalışmaz

Madde 8. Aşağıdaki program ne yazdırır?

values = [10, 20, -1, 30, 0, 40]

for value in values:
    if value == -1:
        break
    if value == 0:
        continue
    print(value)
  • A. 10, 20 ve 30
  • B. 10 ve 20
  • C. 10, 20, -1, 30 ve 40
  • D. 10, 20, 30 ve 40
  • E. Hiçbir şey yazmaz

Madde 9. Aşağıdaki program ne yazdırır?

text = "python"
text.upper()
print(text)
  • A. PYTHON
  • B. Python
  • C. python
  • D. Hata verir; upper() sonucu kullanılmalıdır
  • E. None

Madde 10. Aşağıdaki program ne yazdırır?

line = " Ada Yılmaz,80,90 \n"
parts = line.strip().split(",")
print(parts)
  • A. ['Ada', 'Yılmaz', '80', '90']
  • B. ['Ada Yılmaz', 80, 90]
  • C. Ada Yılmaz 80 90
  • D. ['Ada Yılmaz', '80', '90']
  • E. [' Ada Yılmaz', '80', '90 \n']

Madde 1. Doğru: A. İlk koşul yanlıştır; ikinci koşulda 70 >= 70 doğru olduğu için zincir orada durur.

  • B yanlış: else dalı da bulunduğu için result her durumda bir değere bağlanır.
  • C yanlış: elif zincirinde yalnızca bir dal çalışır; ilk doğru koşuldan sonra zincir biter.
  • D yanlış: else yalnızca önceki koşulların hepsi yanlışsa çalışır.
  • E yanlış: 70 >= 85 yanlıştır; ilk dal seçilmez.

Madde 2. Doğru: E. A’daki iki if deyiminin koşulları ayrı ayrı sınanır, bu yüzden ikinci atama birinciyi ezer. B’de ilk koşul doğru olunca zincir durur ve elif koşuluna hiç bakılmaz.

  • A yanlış: Koşulların sırası mantıksız göründüğü için kodun hatalı olduğu düşünülebilir. Oysa bir koşulun öncekinden dar ya da geniş olması söz dizimini ilgilendirmez; B geçerli bir koddur.
  • B yanlış: elif, else if yazımının kısaltmasına benzediği için yalnız yazım farkı sanılabilir. Oysa elif akışı değiştirir: önceki koşul doğruysa elif koşulu hiç sınanmaz.
  • C yanlış: Sınır değerine bakma alışkanlığı akla önce 50’nin altını getirir. Oysa orada iki kodda da hiçbir dal çalışmaz. Fark, iki koşulun birlikte doğru olduğu değerlerde ortaya çıkar.
  • D yanlış: B’nin sonucunu A’ya da genellemek kolaydır. Ama A’daki ikinci if bağımsızdır ve doğru olduğu için değeri değiştirir.

Madde 3. Doğru: D. for doğrudan değerler üzerinde dolaşır; letter her turda sıradaki karakterdir.

  • A yanlış: İndeksler ancak range(len(word)) veya enumerate() ile elde edilir.
  • B yanlış: Her tur ayrı bir print çağrısıdır; çıktı alt alta gelir.
  • C yanlış: for bir string’in karakterlerini sırayla dolaşabilir.
  • E yanlış: for her turda ikişer karakter almaz; her turda tek bir karakter verir.

Madde 4. Doğru: E. enumerate() her turda sıra numarası ile değeri birlikte verir; ne yapmak istediğiniz koddan kolayca okunur.

  • A yanlış: Çalışır ama indeksi siz yönetirsiniz; enumerate() aynı işi daha kısa yoldan yapar.
  • B yanlış: zip() iki ayrı dizinin elemanlarını eşler; tek bir diziye indeks eklemez.
  • C yanlış: Bu yazım değerleri verir, indeksleri değil.
  • D yanlış: index() aranan değerin konumunu tek bir sayı olarak döndürür; for ile dolaşılacak bir dizi vermez.

Madde 5. Doğru: B. Başlangıç dâhil, bitiş hariçtir. Bu, C’deki i < 7 kalıbına karşılık gelir.

  • A yanlış: Başlangıç değeri dâhildir.
  • C yanlış: Tek argümanlı range(7) bu listeyi verirdi; burada başlangıç 2’dir.
  • D yanlış: Bitiş değeri aralığa dâhil değildir; en sık yapılan hata budur.
  • E yanlış: İki argüman sınırları verir, yalnız o iki sayıyı değil.

Madde 6. Doğru: A. Bitiş değeri aralığa dâhil olmadığı için 10 hiç işlenmiyor. Klasik off-by-one hatasıdır; üst sınırı bir artırmak eksik turu geri getirir.

  • B yanlış: Aralığı değiştirmek doğru yere dokunmak gibi görünür. Ama bu 0 ekler ve 10’u hâlâ dışarıda bırakır; toplam yine 45 kalır.
  • C yanlış: Döngü hatalarında akla önce döngü türünü değiştirmek gelir. Oysa döngü türü sorun değildir; sorun aralığın üst sınırındadır.
  • D yanlış: Eksik toplamı başlangıç değeriyle kapatmak kolay bir yama gibi görünür. Ama bu biriktiriciyi bozar: 1 iki kez sayılır ve sonuç 46 olur.
  • E yanlış: Her terimi biraz büyütmek eksik değeri kapatacakmış gibi görünür. Ama toplam 54 olur; eksik olan tek bir turdur.

Madde 7. Doğru: C. Bir while döngüsünün bitmesi için koşulda geçen değerin her turda değişmesi gerekir. Burada yalnız attempts değişiyor ve o koşulun parçası değil.

  • A yanlış: Ekrana durmadan yazı akması döngünün takıldığı izlenimini verir. print() döngüyü yavaşlatır ama koşulu değiştirmez; döngü yine bitmez.
  • B yanlış: Döngü içinde değişen tek satır bu olduğu için suç ona atılır. Ama attempts koşulda geçmez; koşulu etkilemez.
  • D yanlış: Sonsuz döngü örnekleri çoğunlukla break ile bittiği için böyle bir kural sanılabilir. Oysa koşul yanlış olduğunda döngü kendiliğinden biter; break zorunlu değildir.
  • E yanlış: C’de string’ler strcmp() ile karşılaştırıldığı için bu beklenti doğar. Python’da != string’lerde çalışır ve burada her turda True verir.

Madde 8. Doğru: B. -1 değerinde break döngüyü tümüyle bitirir; 30, 0 ve 40 hiç işlenmez.

  • A yanlış: break sonrasında hiçbir tur açılmaz; 30’a sıra gelmez.
  • C yanlış: -1 yazdırılmadan önce break çalışır.
  • D yanlış: Bu, -1 için de continue yazılmış olsaydı çıkardı; break döngüyü sonlandırır.
  • E yanlış: İlk iki değer break satırına gelmeden yazdırılır.

Madde 9. Doğru: C. String değiştirilemez. upper() yeni bir string döndürür; sonuç bir ada atanmadığı için kaybolur.

  • A yanlış: Bunun için text = text.upper() yazılması gerekirdi.
  • B yanlış: upper() yalnızca ilk harfi değil bütün harfleri büyütür; ayrıca sonucu hiçbir ada atanmıyor.
  • D yanlış: Dönüş değerini kullanmamak hata vermez; kullanılmayan değer kaybolur.
  • E yanlış: print(text) adı yazdırır; metot çağrısının dönüşünü değil.

Madde 10. Doğru: D. Önce strip() baştaki ve sondaki boşlukları, satır sonunu da temizler. Sonra split(",") metni yalnız virgüllerden böler. Parçalar metin olarak kalır.

  • A yanlış: Ayırıcı olarak virgül verildi. Addaki boşluk bir bölme noktası değildir.
  • B yanlış: split() her zaman metin parçaları döndürür. Sayıya çevirmek için ayrıca int() gerekir.
  • C yanlış: split() bir liste döndürür, birleştirilmiş bir metin değil. Birleştirmek join()in işidir.
  • E yanlış: Bu, strip() hiç çağrılmasaydı görülecek sonuçtur. Zincirde strip() bölmeden önce çalışır.

Tek sayfa özet

  • if, for ve while C’dekiyle aynı kavramlardır; Python’da yalnızca yazımları daha sadedir.
  • for yalnızca sayı saymak için değildir; bir listenin ya da metnin elemanlarını sırayla alabilir.
  • Hem indeks hem değer gerektiğinde enumerate(), iki listeyi birlikte dolaşırken zip() kullanılır.
  • break döngüyü bitirir; continue yalnızca mevcut turu atlar.
  • range() son sınırı içermez ve üçüncü parametre adım değeridir.
  • strip, split ve join ile bir metin satırını temizleyip parçalara ayırır, parçaları yeniden birleştirirsiniz. Dosyadan okunan satırlarda bunları sık kullanacağız.
  • String değiştirilemez (immutable); upper() gibi metotlar yeni bir string döndürür.
  • Python’da da sınır değerlerine ve off-by-one hatalarına dikkat etmek gerekir.

Gelecek hafta listeleri ve öteki Python koleksiyonlarını göreceğiz. İki değişkenin aynı listeyi gösterdiği durumlar (referans) ve bir değerin yerinde değiştirilip değiştirilemeyeceği (değiştirilebilirlik) nesne tabanlı programlamada sık karşımıza çıkacak.

Bu bölümün kazanımları

Bu bölümü bitiren öğrenci:

  • if/elif/else zincirinde sınır değerinin hangi dala düştüğünü belirler.
  • Bir listenin ya da metnin elemanları üzerinde indeks kullanmadan dolaşır; enumerate() ile zip()’in hangi durumda gerektiğini ayırt eder.
  • range() bitiş değerinin dışarıda kaldığını bilir ve adım parametresini kullanır.
  • while döngüsünde koşuldaki değeri her turda değiştiren adımın sonsuz döngüyü önlediğini açıklar.
  • break ile continue arasındaki farkı gösterir.
  • String’in değiştirilemez olduğunu ve upper() gibi metotların yeni bir string döndürdüğünü açıklar.
  • strip(), split() ve join() ile bir metin kaydını parçalara ayırır ve birleştirir.
Back to top