PYTHON EĞİTİM SERİSİ · DERS 06 / 16
Bir çalışma planı hazırladığımızı düşünelim. Bugün bir ders okuyacak, birkaç örnek çözecek ve öğrendiklerimizi kısa bir notla özetleyeceğiz. Programımızın bu görevlerin tamamını saklamasını, gerektiğinde yeni görev eklemesini ve bitenleri listeden çıkarmasını istiyoruz.
İlk görev için bir değişken oluşturmak kolaydır. İkinci ve üçüncü görev için de ayrı değişkenler yazabiliriz. Ancak kullanıcı on görev eklediğinde, bunların tamamını göstermek veya belirli bir görevi kaldırmak istediğinde aynı yaklaşım giderek zorlaşır. Artık tek bir değeri saklamaktan, birbiriyle ilgili değerleri birlikte yönetmeye geçmemiz gerekir.
Bu dersin konusu listeler ve demetlerdir. Python’daki list ve tuple türlerini tanıyacak; öğelere erişmeyi, listeyi değiştirmeyi, sıralama ve kopyalama işlemlerini örneklerle inceleyeceğiz. Ardından önceki derslerde öğrendiğimiz koşulları, döngüleri ve metin işlemlerini kullanarak menülü bir çalışma planlayıcısı hazırlayacağız.
Dersin amacı metot adlarını ezberlemek değildir. Bir işlemden önce listenin hangi durumda olduğunu, işlemden sonra neyin değiştiğini ve hangi bilgiyi korumak istediğimizi düşünmeyi öğrenmektir. Bu alışkanlık, ileride daha büyük veri yapılarıyla çalışırken de işimize yarayacak.
Örnekleri listeler_demetler.py dosyasında ayrı ayrı deneyebilirsiniz. Her Python kutusu kendi başına çalışacak şekilde hazırlanmıştır. Çıktı kutularını dosyanıza eklemeyin. Bilerek hatalı örnekleri de diğer örneklerden ayrı çalıştırın.
Ayrı değişkenler yerine neden liste kullanırız?
Bir programı tasarlarken yalnızca bugünkü örneği düşünmek yeterli olmayabilir. Üç görev göstermek için yazdığımız kodun, görev sayısı değiştiğinde de anlaşılır kalmasını isteriz.
Liste, değerleri belirli bir sıra içinde birlikte tutmamızı sağlar. Listeler aynı değeri birden fazla kez içerebilir ve sonradan değiştirilebilir. Başlangıç için Python’un liste açıklamasına da bakabilirsiniz.
Kendi örneğimizde görevleri böyle saklayabiliriz:
gorevler = ["Dersi oku", "Örnek çöz", "Not hazırla"]
print(gorevler)Çıktı:
['Dersi oku', 'Örnek çöz', 'Not hazırla']Burada üç ayrı bilgi kaybolmadı; tek bir liste içinde düzenlendi. Program artık görevlerin tümü için aynı değişkenle çalışabilir. Görev sayısını ölçerken, görevleri ekrana yazdırırken veya yeni bir görev eklerken bu listeyi kullanacağız.
Listeyi yalnızca ekranda görünen köşeli parantezlerden ibaret düşünmeyin. Örneğin ilk öğenin “önce yapılacak iş” anlamına geldiği bir çalışma planında sıra da verimizin parçasıdır. Listeye yapılacak her değişikliği bu anlamı koruyarak değerlendirmemiz gerekir.
Liste oluşturmak ve öğelerin türünü düşünmek
Listeyi köşeli parantezlerle oluşturur, öğeleri virgülle ayırırız. Başlangıçta hiçbir öğe bulunması gerekmiyorsa boş liste kullanabiliriz:
gorevler = []
sureler = [15, 25, 10]
print(gorevler)
print(sureler)Çıktı:
[]
[15, 25, 10]İlk liste kullanıcının ileride gireceği görevleri bekliyor. İkinci liste ise çalışma sürelerini dakika cinsinden içeriyor. Değişken adlarının hangi bilgiyi sakladığımızı anlatması, listeyi okuyacak kişinin işini kolaylaştırır.
Python bir listede farklı türlerde değerler tutmamıza da izin verir. Ancak bunun mümkün olması, her durumda yararlı olduğu anlamına gelmez. Örneğin süreler listesine açıklamasız bir metin eklemek, daha sonra sürelerle hesaplama yapan kodu zorlaştırabilir.
Bu derste görevleri metin, süreleri sayı olarak ayrı örneklerde kullanacağız. Böylece her işlemin sonucunu daha rahat değerlendirebiliriz. Veri türleri konusunda hatırlatmaya ihtiyacınız varsa Değişkenler ve Veri Türleri dersimize dönebilirsiniz.
İndeksleme ve dilimleme: Önceki dersle bağlantı
Metin İşlemleri dersinde konumların sıfırdan başladığını öğrenmiştik. Listelerde de ilk öğenin indeksi 0 olur. Negatif indeksle sondan erişebilir, dilimleme ile bir bölüm alabiliriz:
gorevler = ["Dersi oku", "Örnek çöz", "Not hazırla"]
print(gorevler[0])
print(gorevler[-1])
print(gorevler[:2])Çıktı:
Dersi oku
Not hazırla
['Dersi oku', 'Örnek çöz']İlk iki satır tek bir görev metni verirken son satır iki öğeli bir liste verir. Tek bir öğeye erişmekle bir bölüm almak arasındaki bu farkı koruyun. Sonuç üzerinde yapacağınız işlem, elde ettiğiniz değerin türüne bağlı olacaktır.
Dilimlemede bitiş konumu alınmaz. [:2], başlangıçtan ilerleyip 0 ve 1 numaralı konumları seçer. Bu örneği üç görevden yalnızca ilk ikisini önizlemede göstermek için kullanabiliriz.
Aşağıdaki örnek ise bilerek hatalıdır:
gorevler = ["Dersi oku", "Örnek çöz"]
print(gorevler[2])İki öğeli listede 2 numaralı konum bulunmadığı için IndexError oluşur. Bir listenin var olması, istediğimiz indeksin de var olduğu anlamına gelmez. Özellikle kullanıcı öğe sildikten sonra eski konumlara güvenmekten kaçınmalıyız.
Liste öğeleri değiştirilebilir
Bir görevin adını düzeltmek istediğimizde ilgili konuma yeni değer atayabiliriz:
gorevler = ["Dersi oku", "Örnek çöz"]
gorevler[1] = "İki örnek çöz"
print(gorevler)Çıktı:
['Dersi oku', 'İki örnek çöz']Bu işlem görev sayısını artırmadı. İkinci konumdaki eski değer, yenisiyle değiştirildi. Program tasarımında “düzeltme” ile “yeni kayıt ekleme” işlemlerini ayrı düşünmemiz bu yüzden önemlidir.
Önceki derste metnin bir karakterine doğrudan atama yapamadığımızı görmüştük. Liste bu açıdan farklıdır. Aynı köşeli parantezli erişim biçimini kullanıyor olmamız, farklı veri türlerinin her işlemde aynı davranacağı anlamına gelmez.
Bir diğer ayrıntı da konumların kalıcı kimlik olmamasıdır. Listenin başına yeni görev ekler veya bir görevi silersek diğer öğelerin indeksleri değişebilir. Ekranda “ikinci görev” olarak gösterilen öğe, daha sonra aynı görevi temsil etmeyebilir. Küçük uygulamamızın hangi anda hangi listeyle çalıştığını takip edeceğiz.
Yeni öğe ekleme: append(), insert() ve extend()
Görev eklemek için hangi yöntemi seçeceğimiz, yeni bilginin tek bir öğe mi yoksa birden fazla öğe mi olduğuna bağlıdır.
Sona veya belirli bir konuma ekleme
append() tek öğeyi sona ekler. insert() ise öğeyi verdiğimiz konuma yerleştirir:
gorevler = ["Dersi oku"]
gorevler.append("Örnek çöz")
gorevler.insert(0, "Dosyayı aç")
print(gorevler)Çıktı:
['Dosyayı aç', 'Dersi oku', 'Örnek çöz']İlk görevimiz yerinde kaldı ama başına başka bir görev geldiği için indeksi değişti. Bu örnekte ekleme işleminin sıralamaya etkisini doğrudan görebiliyoruz.
Listeye ekleme yaparken metodu çağırmak yeterlidir. Örneğin gorevler = gorevler.append("Yeni görev") yazmak doğru bir liste güncelleme yaklaşımı değildir: append() listeyi değiştirir ve dönüş değeri None olur. Sonucu liste değişkenine atarsanız elinizdeki listeye o ad üzerinden erişimi kaybedersiniz.
Şimdilik iki adımı zihninizde ayırın: Bir metot listeyi değiştiriyor olabilir; ayrıca kullanmanız gereken bir dönüş değeri olup olmadığına bakmalısınız. Her metodun yeni liste döndürdüğünü varsaymayın.
Birden fazla öğeyi ayrı ayrı ekleme
Başka bir listedeki görevleri mevcut listeye katmak için extend() kullanabiliriz:
gorevler = ["Dersi oku"]
yeni_gorevler = ["Örnek çöz", "Not hazırla"]
gorevler.extend(yeni_gorevler)
print(gorevler)Çıktı:
['Dersi oku', 'Örnek çöz', 'Not hazırla']Aynı değeri append() ile ekleseydik yeni listenin kendisi tek öğe olarak yerleşirdi. Aradaki farkı bağımsız bir örnekle görelim:
gorevler = ["Dersi oku"]
gorevler.append(["Örnek çöz", "Not hazırla"])
print(len(gorevler))
print(gorevler[1])Çıktı:
2
['Örnek çöz', 'Not hazırla']Program hata vermedi, fakat verinin yapısı değişti. Bu kez dış listede iki öğe var; ikincisi kendi başına bir liste. İstediğimiz sonuç üç ayrı görevse doğru yöntemi seçmeliyiz.
Bir hata mesajı görmemek, veri yapısını istediğimiz gibi kurduğumuzu kanıtlamaz. Listelerde işlem sonrası içeriği ve öğe sayısını birlikte kontrol etmek başlangıçta yararlı bir alışkanlıktır.
Öğeyi aramak ve güvenli biçimde kaldırmak
Bir görevin listede bulunup bulunmadığını in ile kontrol edebiliriz. remove() ise verilen değere eşit ilk öğeyi kaldırır:
gorevler = ["Dersi oku", "Örnek çöz", "Dersi oku"]
if "Dersi oku" in gorevler:
gorevler.remove("Dersi oku")
print(gorevler)Çıktı:
['Örnek çöz', 'Dersi oku']Aynı metinden iki tane bulunduğu için yalnızca ilk eşleşme silindi. Başlangıçta “bir görevi tamamlamak” derken hangi kaydı kastettiğimizi belirlemek gerekir. Aynı ada izin veren bir uygulamada yalnızca görev adına göre silme yapmak belirsizlik yaratabilir.
Listede bulunmayan bir değerle remove() çağırmak ValueError oluşturur. Bu örnekte önce üyelik kontrolü yaptığımız için kaldırma kararını açıkça verdik. Hata yönetimini ileride ayrı dersimizde işleyeceğiz.
Konuma göre çıkarma ve çıkan değeri kullanma
Son öğeyi kaldırıp hangi değerin çıktığını öğrenmek için pop() kullanılabilir:
gorevler = ["Dersi oku", "Örnek çöz"]
tamamlanan = gorevler.pop()
print(tamamlanan)
print(gorevler)Çıktı:
Örnek çöz
['Dersi oku']Burada dönüş değerini kullanmak anlamlıydı: Tamamlanan görevi ayrı değişkende tutup ekrana yazdırdık. pop(0) yazsaydık ilk konumdaki öğeyi çıkarırdık. Boş listede pop() çağırmak ise hata verir.
Belirli bir indeksteki öğeyi kaldırıp dönüş değeri kullanmayacaksanız del gorevler[0] da mümkündür. Değer üzerinden silmek, konum üzerinden silmek ve çıkarılan değeri kullanmak farklı ihtiyaçlardır. Bu işlemlerin tanımları Python’un liste metotları belgesinde açıklanır.
Boş liste, len() ve döngüyle gösterim
Kullanıcı hiç görev eklemediğinde de anlaşılır çıktı üretmeliyiz. İlk veya son öğeye erişmeden önce listenin boşluğunu değerlendirebiliriz:
gorevler = []
if gorevler:
print(gorevler[-1])
else:
print("Henüz görev yok.")Çıktı:
Henüz görev yok.Boş liste koşulda yanlış kabul edilir. Böylece kullanıcıya bir hata yerine durumunu anlatan mesaj veririz. Bu kontrolü yalnızca programın başında düşünmeyin; son görev tamamlandığında liste yeniden boşalabilir.
Bütün görevleri göstermek için daha önce öğrendiğimiz for döngüsünden yararlanabiliriz. Numaralı gösterim gerektiğinde enumerate() her öğeyle birlikte bir sayaç değeri sağlar:
gorevler = ["Dersi oku", "Örnek çöz"]
for numara, gorev in enumerate(gorevler, start=1):
print(f"{numara}. {gorev}")
print(f"Toplam: {len(gorevler)}")Çıktı:
1. Dersi oku
2. Örnek çöz
Toplam: 2start=1, ekrandaki sayacı birden başlatır; listenin gerçek indekslerini değiştirmez. Okurun gördüğü “1.” ile Python’un kullandığı indeks 0 arasındaki farkı koruyun. enumerate() belgesindeki başlangıç parametresi bu gösterimi sağlar.
Bu bölüm, Döngüler dersindeki bilgiyi yeni bir veri yapısıyla birleştiriyor. Döngüyü öğrenirken görevimizi tek tek tekrarlıyorduk; şimdi tekrarlanan işlemin hangi öğeler üzerinde çalışacağını liste belirliyor.
Sıralama yaparken özgün sırayı korumak
Süreleri küçükten büyüğe görmek istediğimizde sorted() kullanarak yeni bir liste alabiliriz:
sureler = [25, 10, 40]
sirali_sureler = sorted(sureler)
print(sirali_sureler)
print(sureler)Çıktı:
[10, 25, 40]
[25, 10, 40]İlk liste sıralanmış görünümü, ikinci çıktı özgün sırayı gösteriyor. Çalışma planında kullanıcı sırası önemliyse bu ayrım değerlidir. Bir raporu düzenli göstermek için planın kendisini değiştirmek zorunda olmayabilirsiniz.
sureler.sort() ise mevcut listeyi yerinde sıralar ve None döndürür. sorted() ile sort() arasındaki temel farkı Python’un sıralama rehberinde inceleyebilirsiniz.
Bu örnekte sayıları kullandık. Farklı türleri gelişigüzel aynı listede sıralayabileceğinizi varsaymayın. Metinleri sıralamak da Türkçe sözlük sırasının otomatik uygulanacağı anlamına gelmez. İhtiyacınız sayısal sıralama mı, kullanıcı önceliği mi, yoksa belirli bir dilde alfabetik sıralama mı; önce bunu belirleyin.
Atama ile kopyalama neden aynı değildir?
Bir listeyi başka değişkene atadığımızda bağımsız bir liste üretmiş olmayız:
plan = ["Dersi oku"]
diger_ad = plan
diger_ad.append("Örnek çöz")
print(plan)Çıktı:
['Dersi oku', 'Örnek çöz']İşlemi diger_ad üzerinden yaptık, fakat plan çıktısında da değişikliği gördük. İki ad aynı listeye bağlıydı. Bu davranışı bilmeden bir “yedek” değişken oluşturduğunuzu sanabilirsiniz.
Bu dersteki gibi metinlerden oluşan bir listenin ayrı kopyasını copy() ile alabiliriz:
plan = ["Dersi oku"]
deneme = plan.copy()
deneme.append("Örnek çöz")
print(plan)
print(deneme)Çıktı:
['Dersi oku']
['Dersi oku', 'Örnek çöz']Böylece deneme listesine ekleme yaptığımızda özgün plan değişmedi. Ancak copy() sığ kopya üretir. Listenin içinde başka listeler gibi değiştirilebilir nesneler bulunuyorsa onların tamamen bağımsız kopyalandığını düşünmemeliyiz. Bu sınır Python’un kopyalama açıklamasında ele alınır.
Şimdilik kendi çalışma planımız metin öğelerinden oluştuğu için kopya üzerinde görev ekleyip çıkarma örneğini rahatça izleyebiliriz. Daha karmaşık yapılarda, hangi katmanın kopyalandığını ayrıca değerlendirmemiz gerekir.
Demet (tuple): Bir arada duran, öğeleri değiştirilemeyen değerler
Görev listemiz gün içinde büyüyüp küçülebilir. Buna karşılık bir çalışma oturumunun adını ve hedef süresini birlikte taşımak isteyebiliriz: “Sabah tekrarı” ve 25 dakika. Bu iki değerin sırasını belirleyip tek bir kayıt gibi kullanırken demet işimize yarar.
Demet, İngilizce adıyla tuple, sıralı bir veri yapısıdır. Listelerde kullandığımız indeksleme burada da geçerlidir. Ancak oluşturduğumuz demetin bir konumuna sonradan başka bir değer atayamayız.
oturum = ("Sabah tekrarı", 25)
print(oturum[0])
print(oturum[1])Çıktı:
Sabah tekrarı
25Bu örnekte sıfırıncı konum oturumun adını, birinci konum dakika bilgisini temsil ediyor. Bu anlaşmayı kodun devamında korursak aynı kaydı farklı yerlerde kullanabiliriz. Öğelerin ne anlama geldiğini açıklayan değişken adları seçmek, yalnızca parantez türüne odaklanmaktan daha önemlidir.
Aşağıdaki örnek bilerek hatalıdır; önceki örneğin devamına eklemek yerine ayrı çalıştırın:
oturum = ("Sabah tekrarı", 25)
oturum[1] = 30Python burada TypeError verir. Demetin ikinci öğesini yerinde değiştirmeye çalışıyoruz. Yeni bir oturum kaydı üretmek istersek aynı değişkene başka bir demet atayabiliriz; bu işlem eski demetin içini değiştirmek değildir.
Bir ayrıntıyı da gözden kaçırmayalım: Demetin içinde bir liste bulunabilir ve o listenin içeriği değişebilir. Dolayısıyla “demet kullandım, içindeki her şey sonsuza kadar sabitlendi” sonucu çıkmaz. Bu dersteki oturum kaydında metin ve tam sayı kullanmamız, örneği bu ek katmandan uzak tutuyor. Demetlerin bu davranışı Python’un resmî demet açıklamasında da belirtilir.
Tek öğeli demette virgül neden önemlidir?
İki öğeli örneğimizde parantez içinde virgül zaten vardı. Tek öğe olduğunda virgülü unutmak ise veri türünü değiştirebilir:
metin = ("Tekrar")
tek_oge = ("Tekrar",)
print(type(metin))
print(type(tek_oge))
print(len(tek_oge))Çıktı:
<class 'str'>
<class 'tuple'>
1İlk satırdaki parantez yalnızca metin ifadesini çevreliyor. İkinci satırdaki virgül, tek öğeli demet oluşturduğumuzu belirtiyor. Boş demet için () kullanılır. Başlangıçta parantezleri yazmak, kodu okurken demeti görmeyi kolaylaştırır; tek öğeli kullanımda asıl ayırt edici işareti unutmayın.
Demeti değişkenlere açmak
Oturum adı ve süreyi sürekli oturum[0] ve oturum[1] diye kullanabiliriz. Ancak bu iki bilginin anlamını değişken adlarında göstermek daha okunaklı olur:
oturum = ("Sabah tekrarı", 25)
oturum_adi, dakika = oturum
print(f"{oturum_adi}: {dakika} dakika")Çıktı:
Sabah tekrarı: 25 dakikaBu işleme açma, yani unpacking denir. Buradaki sade kullanımda soldaki iki değişken, sağdaki iki öğeyi sırayla alır. Üç öğeyi iki değişkene açmaya çalışırsak ValueError oluşur. Bu nedenle kaydın biçimini bilmeden değişken sayısını tahmin ederek ilerlememeliyiz.
Önceki bölümdeki for numara, gorev in enumerate(...) satırını da artık daha rahat okuyabiliriz. Döngünün her adımında gelen numara ve görev bilgisi, iki değişkene ayrılıyor. Böylece ekranda hem insanın takip edeceği sıra numarasını hem görev metnini birlikte gösterebiliyoruz.
Liste mi, demet mi seçmeliyiz?
Çalışma planındaki görevler için liste seçmemizin nedeni, ekleme ve çıkarma işlemlerinin programın doğal bir parçası olması. Oturum adı ile süresi için demet seçmemizin nedeni ise bu iki bilgiyi belirli sıraya sahip bir kayıt olarak birlikte taşımak istememiz.
| İhtiyaç | Bu dersteki uygun tercih | Örnek |
|---|---|---|
| Gün içinde görev eklemek ve tamamlananı çıkarmak | Liste | ["Dersi oku", "Örnek çöz"] |
| Bir oturumun adını ve süresini birlikte taşımak | Demet | ("Sabah tekrarı", 25) |
| İlk birkaç görevi göstermek | Liste dilimi | gorevler[:3] |
| Menü seçeneklerini belirlenmiş sırada göstermek | Demet kullanılabilir | ("Ekle", "Göster", "Çıkış") |
Bu tablo, her sabit görünen bilginin mutlaka demet olması gerektiği anlamına gelmiyor. Önce programın hangi işlemleri yapacağını düşünün. Bir menüyü kullanıcıların düzenleyebileceği bir uygulama tasarlasaydık, seçenekleri listede tutmak daha uygun olabilirdi. Bu dersteki menüyü ise program çalışırken değiştirmiyoruz.
Aynı şekilde demet seçmek erişim yetkisi tanımlamaz ve tek başına güvenlik sağlamaz. Amacımız verinin yapısını ve hangi işlemleri beklediğimizi kodda açık etmek. Küçük örneklerde bu seçim önemsiz görünebilir; program büyüdükçe “bu grup değişecek mi?” sorusuna verdiğimiz cevap işimizi kolaylaştırır.
Gerektiğinde list(oturum) ile yeni bir liste, tuple(gorevler) ile yeni bir demet oluşturabiliriz. Bu dönüşümler mevcut değişkenin türünü kendiliğinden değiştirmez; üretilen sonucu kullanmamız gerekir. İç içe yapılar varsa, tür dönüşümünün bütün iç nesneleri bağımsız kopyaladığı varsayımına da kapılmamalıyız.

Küçük proje: Günlük çalışma planlayıcısı
Şimdi öğrendiklerimizi tek bir programda birleştirelim. Program görev eklesin, görevleri numaralı göstersin ve tamamlanan görevi listeden çıkarsın. Menü seçeneklerini demette, kullanıcının görevlerini listede tutacağız.
Tamamlama işlemini görev adına göre yapacağız. Böylece henüz hata yönetimini öğrenmeden, kullanıcıdan gelen rastgele bir metni sayıya çevirmek zorunda kalmayacağız. Görev adı listede varsa çıkaracağız; yoksa açıklayıcı bir mesaj vereceğiz.
Aşağıdaki kodu calisma_plani.py adıyla kaydedip çalıştırabilirsiniz. Türkçe karakterleri korumak için dosyayı UTF-8 biçiminde kaydedin.
gorevler = []
menu = (
"1 - Görev ekle",
"2 - Görevleri göster",
"3 - Görevi tamamla",
"0 - Çıkış",
)
while True:
print("\nÇALIŞMA PLANI")
for satir in menu:
print(satir)
secim = input("Seçiminiz: ").strip()
if secim == "1":
yeni_gorev = input("Görev: ").strip()
if not yeni_gorev:
print("Görev boş bırakılamaz.")
elif yeni_gorev in gorevler:
print("Bu görev zaten listede.")
else:
gorevler.append(yeni_gorev)
print("Görev eklendi.")
elif secim == "2":
if not gorevler:
print("Henüz görev yok.")
else:
for numara, gorev in enumerate(gorevler, start=1):
print(f"{numara}. {gorev}")
elif secim == "3":
if not gorevler:
print("Tamamlanacak görev yok.")
else:
tamamlanan = input("Tamamlanan görevin adı: ").strip()
if tamamlanan in gorevler:
gorevler.remove(tamamlanan)
print(f"Tamamlandı: {tamamlanan}")
else:
print("Görev bulunamadı.")
elif secim == "0":
print("Çalışma planı kapatıldı.")
break
else:
print("Geçerli bir seçim yapın.")Programın akışını adım adım okuyalım
İlk satırdaki boş liste, o çalıştırma oturumunun görevlerini tutuyor. Bu satırın döngüden önce bulunması önemli. Listeyi while bloğunun en başında tekrar oluştursaydık, her menü dönüşünde görevleri sıfırlardık. Değişkenin nerede oluşturulduğu, verinin ne kadar süre korunacağını doğrudan etkiliyor.
Menü demetini de döngüden önce tanımladık. Her turda bu demetin içeriğini for ile gösteriyoruz; seçeneklerin kendisini değiştirmiyoruz. Menüden yapılan seçim bir metin olduğu için karşılaştırmalarımızda "1", "2" gibi metin değerleri var. Burada input() sonucunun kendiliğinden tam sayıya dönüşmediğini hatırlayın.
Görev eklerken strip(), baştaki ve sondaki boşlukları temizliyor. Ardından boş metni reddediyoruz. Bu kontrol olmazsa kullanıcı yalnızca boşluk yazıp listede görünüşte boş bir satır oluşturabilir. Görev içindeki sözcüklerin arasındaki boşlukları ise bu yöntem kendiliğinden düzenlemez.
Bir sonraki kontrol, aynı görev metninin listede bulunup bulunmadığı. Bu programda aynı yazılışa sahip görevi ikinci kez eklemiyoruz. Ancak “Dersi oku” ile “dersi oku” farklı metinlerdir. Kontrol büyük ve küçük harfe duyarlıdır; programın bütün benzer görevleri anlayıp birleştirdiğini düşünmeyin.
Gösterme bölümünde boş listeye özel mesaj veriyoruz. Liste doluysa enumerate() ile ekranda birden başlayan sıra numaraları üretiyoruz. Görev tamamlandıktan sonra listede kalanlar yeniden numaralanır. Bu numaralar görevlerin kalıcı kimliği değildir; yalnızca o anki görünümdeki yerlerini gösterir.
Tamamlama bölümünde önce listenin boş olup olmadığını denetliyoruz. Görev varsa kullanıcıdan adını istiyoruz. in kontrolünün ardından remove() çağırmak, bulunamayan bir görevi çıkarmaya çalışmamızı önlüyor. Son görevi de çıkardığımızda liste yeniden boş hale gelir; program aynı menüyle çalışmayı sürdürür.
Son olarak break yalnızca çıkış seçeneğinde devreye giriyor. Kullanıcı beklenmeyen bir seçim yaparsa program kapanmıyor; geçerli seçim istemeye devam ediyor. Bu akış, önceki derslerdeki koşul ve döngü bilgisini bir veri yapısıyla birleştiren küçük ama tamamlanmış bir örnektir.
Örnek kullanımda hangi değişiklikleri görmeliyiz?
Programı açtıktan sonra önce 2 seçeneğini deneyin. Henüz görev eklemediğiniz için boş liste mesajını görmelisiniz. Ardından 1 seçeneğiyle “Dersi oku”, bir kez daha 1 ile “Örnek çöz” görevini ekleyin.
Tekrar 2 seçtiğinizde “Dersi oku” birinci, “Örnek çöz” ikinci sırada görünür. Burada ekleme sırasının korunduğunu gözleyebilirsiniz. Aynı adla bir görev daha eklemeyi deneyince tekrar uyarısı gelmeli; listedeki görev sayısı artmamalıdır.
Şimdi 3 seçeneğinde “Dersi oku” yazın. Program bu görevi çıkarır. Bir sonraki gösterimde yalnızca “Örnek çöz” kalır ve ekrandaki numarası 1 olur. Listeyi yazdırmak yerine yalnızca çıkarma mesajına bakarsanız bu sıra değişikliğini kaçırabilirsiniz; iki adımı birlikte deneyin.
Programı 0 ile kapatıp yeniden açtığınızda önceki görevler geri gelmez. Çünkü veriyi yalnızca programın belleğinde tutuyoruz. Dosyaya kaydetmeyi serinin ilerleyen dersinde ele alacağız. Bu davranış şu anki örneğin beklenen sınırıdır; kayıt özelliği varmış gibi değerlendirmeyin.
Listeyle çalışırken sık yapılan hatalar
Listeyi dolaşırken aynı listeden öğe çıkarmak
Bir döngüyle görevleri dolaşırken, aynı listenin içinden öğe silmek sonraki öğelerin yerini değiştirir. Bu nedenle bazı öğeleri atlayan sonuçlar görebilirsiniz. Bütün öğelere belli bir ölçüt uygulamak istediğimizde, başlangıç için sonucu ayrı listede toplamak daha anlaşılırdır:
gorevler = ["Dersi oku", "", "Örnek çöz", " "]
temiz_gorevler = []
for gorev in gorevler:
duzenlenmis = gorev.strip()
if duzenlenmis:
temiz_gorevler.append(duzenlenmis)
print(temiz_gorevler)
print(gorevler)Çıktı:
['Dersi oku', 'Örnek çöz']
['Dersi oku', '', 'Örnek çöz', ' ']Burada özgün listeyi dolaştık fakat değiştirmedik. Temizlenmiş, boş olmayan görevleri başka bir listede biriktirdik. İkinci çıktı, başlangıç verisinin hâlâ yerinde durduğunu gösteriyor. Sonucu ayrıca inceleyebilmek, beklemediğimiz bir temizlik yapıp yapmadığımızı anlamamızı da kolaylaştırır.
Örnekte boş görünen metinle boş listeyi birbirine karıştırmayın. [""] bir öğeli listedir; içindeki metin boştur. [] ise hiç öğesi olmayan listedir. Bu ayrım, kullanıcıdan alınan verilerde neden hem listeye hem metnin kendisine bakmamız gerektiğini açıklar.
Ekrandaki numarayı doğrudan indeks sanmak
İlk görevi ekranda 1 diye gösterdik, ama listenin ilk indeksi hâlâ 0. İleride numarayla silme özelliği eklerken bu farkı hesaba katmalıyız. Kullanıcı 1 yazdığında ikinci görevi silen bir program, çalışıyor görünse bile yanlış sonuç üretir.
Üstelik yalnızca bir çıkarmak yetmez: Girilen metnin geçerli bir sayı olduğunu ve sayının mevcut görev aralığında bulunduğunu da denetlemek gerekir. Bu derste adla tamamlama seçmemizin nedeni, liste mantığını öğrenirken bu ek giriş kontrollerini aynı anda yüklememek.
İşlem sonucuyla değişen listeyi karıştırmak
Bir satırın ekranda sonuç üretmesi, yeni liste döndürmesi ve mevcut listeyi değiştirmesi farklı şeylerdir. append() ile ekleme yaptıktan sonra değişen listeyi görmek için listeyi yazdırırız. pop() ise çıkardığı öğeyi ayrıca verir. sorted() yeni bir sıralı liste üretir.
Bir yöntemi kullanırken “Bu işlemden sonra hangi değişken neyi tutuyor?” sorusunu sorun. Küçük bir print() kontrolüyle önceki ve sonraki durumu görmek, yöntem adlarını ezberlemekten daha öğreticidir. Özellikle None gördüğünüzde doğrudan verinin silindiğini varsaymak yerine, yazdırdığınız ifadenin ne döndürdüğünü inceleyin.
Öğrendiklerinizi geliştirecek üç alıştırma
1. Öncelik görünümü ekleyin. Planlayıcıya, ilk üç görevi gösteren yeni bir menü seçeneği ekleyin. Tüm listeyi değiştirmeden bir dilim üzerinde gösterim yapın. Sıfır, iki ve beş görevle deneyin. İki görev varken programın üçüncü bir öğe arayıp hata vermemesi gerekir.
Bu alıştırmada amaç dilimlemeyi yalnızca sözdizimi olarak kullanmak değildir. “Önce neye odaklanacağım?” sorusuna ayrı bir görünüm üretirken görevlerin tamamını koruyabildiğinizi görmektir. Gösterimden sonra normal listeleme seçeneğine dönerek diğer görevlerin kaybolmadığını kontrol edin.
2. Sıradaki görevi tamamlayın. Ad yazmadan ilk görevi tamamlayan bir seçenek oluşturun. Liste boş değilse pop(0) kullanıp çıkan görevi mesajda gösterin. Boşsa açıklama yazdırın. Ardışık iki görev ekleyip bu seçeneği üç kez çalıştırarak boş liste kontrolünü sınayın.
Burada “sıradaki” sözcüğünün ekleme sırasındaki ilk görev anlamına geldiğini açık tutun. Daha önce görevleri yerinde sıralarsanız programın sıradaki görevi de değişir. İşlem sırası ile uygulamanın kullanıcıya verdiği söz arasındaki ilişkiyi bu küçük örnekte görebilirsiniz.
3. Çalışma süreleri raporu hazırlayın. Ayrı bir örnekte [25, 10, 40, 15] sürelerini kullanın. Küçükten büyüğe sıralı görünümü yeni bir değişkende tutun; başlangıç listesini de yazdırın. Ardından en kısa süreyi sıralı görünümden alın ve açıklayıcı bir cümle içinde gösterin.
Bu kez görev adları yerine sayılarla çalışıyoruz, ama veri yapısı yine liste. Aynı araçları farklı içeriklerle kullanabildiğinizi fark edin. Boş bir süre listesinde ilk öğeyi okumadan önce neyi kontrol etmeniz gerektiğini de ayrıca düşünün. Doğru sonuç kadar, veri olmadığında programın nasıl davranacağını tasarlamak da öğrenmenin bir parçasıdır.
Bu dersten sonra hangi noktaya geldik?
Artık birden fazla değeri tek bir listede toplayabilir, öğelere erişebilir, ekleme ve çıkarma yapabilir, bunları döngüyle gösterebilirsiniz. Listeyi başka bir değişkene atamakla kopyalamak arasındaki farkı da gördük. Demetlerle ise sırası belli değerleri birlikte taşıyıp gerektiğinde açıklayıcı değişkenlere açtık.
Bu bilgileri küçük çalışma planlayıcısında birleştirdik. Önemli olan yalnızca menünün açılması değil; boş giriş, yinelenen görev ve bulunamayan kayıt gibi durumlarda ne olduğunu açıklayabilmeniz. Kodu değiştirirken önce beklediğiniz sonucu söyleyin, sonra çalıştırıp gerçek sonuçla karşılaştırın.
Bir sonraki dersimiz Sözlükler ve Kümeler olacak. Bir bilgiyi sıra numarası yerine anlamlı bir anahtarla bulmayı ve tekrar eden değerlerle farklı biçimde çalışmayı ele alacağız. Bu dersteki liste mantığını oturtmak, yeni yapıların hangi sorunları çözdüğünü anlamamızı kolaylaştıracak.
PYTHON EĞİTİM SERİSİ · DERS 06 / 16
Sonraki: Sözlükler ve Kümeler →
Yeni rehberleri kaçırmayın
Yeni teknoloji rehberleri ve pratik çözümler e-postanıza gelsin.




