Koleksiyonlar, değiştirilebilirlik ve referans sezgisi

Nesne tabanlı programlamaya geçmeden önce iki şeyi bilmemiz gerekiyor: Python’da birden fazla değer nasıl tutulur ve bir değişken adı bir değeri nasıl gösterir? Bu hafta liste, demet, sözlük ve kümeyi kısaca kullanacağız. En çok üç konu üzerinde duracağız: değiştirilebilirlik (mutability), yani bir değerin oluşturulduktan sonra değişip değişemeyeceği; aynı nesneyi paylaşma (aliasing), yani iki adın aynı nesneyi göstermesi; ve kopyalama. Dört koleksiyonun bütün ayrıntılarını tek haftada ezberlemeniz beklenmiyor.

Bu bölümün kapsamı

NoteSınavda sorulur
  • list, tuple, dict ve set arasından uygun koleksiyonu seçme
  • Demet değişmez olsa da içindeki değiştirilebilir nesnenin değişebilmesi
  • b = a sonrası iki adın aynı nesneyi göstermesi
  • is ile == farkı
  • copy() ile bağımsız kopya almak; sığ kopyada neyin ortak kaldığı
  • Sözlükte .keys(), .values() ve .items() görünümleri
  • sorted() ile .sort() farkı
  • copy.deepcopy() ayrıntıları
  • collections modülündeki yardımcı yapılar
  • Küme işlemleri (birleşim, kesişim) ayrıntısı

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

İki değişken aynı listeyi ne zaman gösterir?

C’de iki int ya da iki struct değişkeni için b = a yazdığınızda a’daki değer b’ye kopyalanırdı. Python’da iki liste adı için aynı satır kopya almaz: iki ad aynı listeyi gösterir ve birinden yaptığınız değişikliği öteki de görür. Bu bölümde koleksiyon türlerini ezberlemekten çok bu durumu inceleyeceğiz. Nesne tabanlı programlamaya geçtiğimizde en çok bu fikre ihtiyacımız olacak.

NoteBu haftanın önceliği

Ders süresi yetmezse set ayrıntılarını ve iç içe listelerle sığ kopya örneklerini sonraya bırakabiliriz. Sonraki haftalar için şunu iyice kavrayın: iki ad aynı değiştirilebilir nesneyi gösterebilir ve bir addan yapılan değişiklik ötekinden de görülür.

Dört temel koleksiyon

Yapı Temel fikir Değiştirilebilir? Tipik kullanım
list sıralı değerler evet notlar, ürünler, adımlar
tuple sabit sıralı grup hayır koordinat, değişmez kayıt parçası
dict anahtar → değer evet öğrenci no → öğrenci bilgisi
set benzersiz değerler evet üyelik, tekrarları kaldırma

Kümede "python" iki kez yazılsa bile yalnızca bir kez tutulur.

Liste değişir, demet değişmez

Aynı işlemi bir tuple’da denerseniz TypeError alırsınız:

point = (10, 20)
point[0] = 99  # hata

Tuple’ın değiştirilemez olması şu anlama gelir: point[0] gibi bir konuma sonradan başka bir değer atanamaz. Ama tuple’ın içinde liste gibi değiştirilebilir bir nesne durabilir:

Tuple’ın hiçbir konumuna yeni değer atamadık; tuple’ın içindeki listeye bir eleman ekledik. Demek ki “immutable (değiştirilemez)” sözcüğü “içindeki her şey de değişmez” anlamına gelmez.

Bir demetin kendisi değişmezken içinde tuttuğu değiştirilebilir nesnenin durumunun değişebildiğini gösteren diyagram.

Demet içinde değiştirilebilir nesne

Deney: iki ad, bir liste

Aşağıdaki kodu çalıştırmadan önce çıktıyı tahmin edin.

second = first yeni bir liste oluşturmaz. İki değişken adı aynı liste nesnesini gösterir.

İki adın aynı listeyi göstermesi ile bağımsız bir kopya oluşturulması arasındaki fark.

Aliasing ve kopya

id() her nesneye özgü bir kimlik numarası döndürür. İki adın id() değeri aynıysa ikisi aynı nesneyi gösteriyordur. Aynı soruyu is ile de sorabiliriz:

is, iki ifadenin aynı nesneyi gösterip göstermediğini sorar. == ise iki değerin eşit sayılıp sayılmadığını sorar.

ImportantBu fikir OOP’de sürekli karşımıza çıkacak

Gelecek haftalarda account, customer, order gibi değişkenler de birer nesneyi gösterecek. Bir nesneyi metotla (bu haftaki .append() gibi) değiştirdiğimizde, aynı nesneyi gösteren öteki adlar da yeni durumu görür. Bugünkü liste deneyi bunun küçük bir örneği.

Eşit ama aynı olmayan iki liste

İçerikleri eşit, ama bunlar iki ayrı liste nesnesi.

Kopya oluşturmak

Ayrı bir liste istiyorsak en açık yollardan biri .copy() çağırmaktır:

Aynı dış listeyi list(original) veya original[:] ile de kopyalayabilirsiniz; bu derste okuması kolay olduğu için .copy() kullanacağız.

.copy() bir sığ kopya (shallow copy) alır: yalnızca dıştaki listeyi kopyalar. İç içe listelerde içteki listeler iki kopya arasında hâlâ ortaktır:

Bu hafta deepcopy ayrıntısına girmiyoruz. Yine de kopya aldığınızda neyin ayrıldığını, neyin ortak kaldığını kendinize sormayı alışkanlık hâline getirin.

Sözlükle kayıt tutmak ve dolaşmak

Bir sözlüğü doğrudan for ile dolaşırsanız yalnızca anahtarları alırsınız. Anahtarla değeri birlikte kullanmak için çoğu zaman .items() yazılır:

  • .keys() anahtarları,
  • .values() değerleri,
  • .items() (anahtar, değer) çiftlerini verir.

Bu üç metodun döndürdüğü nesnelere görünüm (view) denir. Yukarıdaki gibi list() ile listeye çevrilebilirler.

Sözlük anahtarı neden her şey olamaz?

Sözlük ve küme, bir değeri hızlı bulmak için o değerden hesaplanan bir sayı kullanır. Bu sayıya hash denir. Bu yüzden sözlük anahtarının hashlenebilir olması, yani hash değerinin hesaplanabilmesi ve hiç değişmemesi gerekir. Başlangıç için şu kural yeter: değiştirilebilir list, dict ve set nesnelerini anahtar yapmayın:

lookup = {}
lookup[[1, 2]] = "değer"  # TypeError: unhashable type: 'list'

str, int ve içinde yalnızca değiştirilemez değerler bulunan tuple’lar sık kullanılan anahtarlardır. 12. haftada kendi yazdığımız sınıflarda bu konuya __eq__ metoduyla birlikte döneceğiz.

sorted() ve .sort()

İki isim benzer, etkileri farklıdır:

  • sorted(iterable) yeni bir liste döndürür; verilen koleksiyonu değiştirmez.
  • list.sort() mevcut listeyi yerinde değiştirir ve None döndürür.

İleride nesnelerden oluşan listeleri sıralarken de bu ayrım geçerli olacak.

Alıştırma: Doğru koleksiyonu seç

Aşağıdaki her ihtiyaç için list, tuple, dict ve set arasından en uygununu seçin ve nedenini bir cümleyle yazın:

  1. Bir dersin haftalık konu sırası.
  2. Öğrenci numarasından öğrenci adına hızlı erişim.
  3. Sisteme giriş yapan benzersiz kullanıcı adları.
  4. Değişmemesi gereken (enlem, boylam) çifti.

Tek bir doğru cevap aramayın; kullanım amacına bakın.

Alıştırma: Aliasing hatasını düzelt

Aşağıdaki kodda backup listesinin değişmeden kalması gerekiyor:

backup ayrı bir liste olsun diye tek bir satırı .copy() kullanarak değiştirin.

Alıştırma: Frekans sözlüğü

counts.get(word, 0) ifadesi anahtar yoksa 0 döndürür.

counts[word] = counts.get(word, 0) + 1

Sıra sizde: Basit envanter

Ürün kodlarını anahtar, stok miktarlarını değer olarak tutan bir sözlük oluşturun. Ardından:

  • Bir ürünün stokunu azaltın,
  • Sözlükte olmayan bir ürünü program hata vermeden sorgulayın,
  • .items() ile dolaşıp stoku sıfır olan ürünleri listeleyin,
  • Ürün kodlarını sorted() ile sıralayıp yazdırın,
  • Ürün kodlarının neden benzersiz kaldığını açıklayın.

Son olarak şu soruyu cevaplayın: “Stok sıfırın altına düşmesin” kuralını bu sözlük yaklaşımında nerede koruyoruz? Bu sorunun cevabı, ileride sınıf metotlarına neden ihtiyaç duyacağımızı gösterecek.

Çalışır kod görevi: Envanter programını üç durumla çalıştırın: sözlükte olan bir ürün, olmayan bir ürün ve stoku sıfır olan bir ürün. Üç durum da çıktıda görünmeli.

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. Bir metindeki benzersiz kelimeleri tutmak için en uygun koleksiyon hangisidir?

  • A. tuple; değiştirilemez olduğu için tekrar eklenemez
  • B. set; aynı değeri yalnız bir kez tutar
  • C. list; sıra korunduğu için tekrar sorunu oluşmaz
  • D. str; kelimeler zaten metin olduğu için
  • E. dict; anahtarlar sıralı tutulduğu için

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

record = ("Ada", [70, 80])
record[1].append(90)
print(record)
  • A. ('Ada', [70, 80, 90]); demetin içindeki liste değişir
  • B. ('Ada', [70, 80], 90)
  • C. TypeError; demet değiştirilemez
  • D. ('Ada', [70, 80]); demet içindeki liste kopyalanır
  • E. AttributeError; demet elemanlarında metot çağrılamaz

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

first = [10, 20]
second = first
second.append(30)

print(first)
print(second)
  • A. [10, 20, 30] ve [10, 20]
  • B. [10, 20] ve [10, 20, 30]
  • C. [10, 20, 30] ve [30]
  • D. Her iki satırda da [10, 20, 30]
  • E. Hata verir; bir listeyi iki ada bağlamak yasaktır

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

def ekle(liste):
    liste.append(99)

sayilar = [1, 2]
ekle(sayilar)
print(sayilar)
  • A. [1, 2, 99]; liste aynı nesneyi gösterir
  • B. [1, 2]; fonksiyon kendi kopyası üzerinde çalışır
  • C. None
  • D. Hata verir; fonksiyon dışındaki liste değiştirilemez
  • E. [99]

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

a = [1, 2]
b = [1, 2]

print(a == b)
print(a is b)
  • A. False ve False
  • B. Hata verir; listelerde is kullanılamaz
  • C. True ve True
  • D. False ve True
  • E. True ve False

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

original = [10, 20]
copy = original.copy()
copy.append(30)

print(original)
print(copy)
  • A. Hata verir; copy yerleşik bir addır ve değişken olarak kullanılamaz
  • B. [10, 20] ve [30]
  • C. [10, 20] ve [10, 20, 30]
  • D. [10, 20, 30] ve [10, 20]
  • E. Her iki satırda da [10, 20, 30]

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

original = [[1, 2], [3, 4]]
copy = original.copy()
copy[0].append(99)

print(original)
  • A. [[1, 2], [3, 4]]; kopya tümüyle bağımsızdır
  • B. TypeError; kopyalanmış listenin elemanları değiştirilemez
  • C. [[1, 2], [3, 4], 99]
  • D. [[99], [3, 4]]
  • E. [[1, 2, 99], [3, 4]]; iç listeler hâlâ paylaşılır

Madde 8. stocks = {"P100": 2, "P200": 0} iken for x in stocks: döngüsünde x neyi alır?

  • A. Anahtar ve değerleri sırayla tek tek
  • B. Anahtarları; değer de gerekiyorsa .items() kullanılmalıdır
  • C. (anahtar, değer) çiftlerini
  • D. Hata verir; sözlük üzerinde doğrudan dolaşılamaz
  • E. Değerleri

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

scores = [80, 60, 90]
ordered = sorted(scores)
print(scores)
print(ordered)
  • A. [60, 80, 90] ve None
  • B. Hata verir; sorted bir değişkene atanamaz
  • C. Her iki satırda da [80, 60, 90]
  • D. [80, 60, 90] ve [60, 80, 90]
  • E. Her iki satırda da [60, 80, 90]

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

scores = [80, 60, 90]
result = scores.sort()
print(result)
  • A. Hata verir; sort() dönüş değeri bir değişkene atanamaz
  • B. [80, 60, 90]
  • C. None; list.sort() listeyi yerinde sıralar ve değer döndürmez
  • D. [60, 80, 90]
  • E. True

Madde 1. Doğru: B. Küme tekrarları kendiliğinden eler ve “bu kelime var mı?” sorusuna doğrudan cevap verir. Sıra önemli değilse en doğrudan seçimdir.

  • A yanlış: Değiştirilemezliği “tekrar eklenemez” diye okumak kolaydır. Oysa değişmezlik tekrar içermediği anlamına gelmez; ("a", "a") geçerlidir.
  • C yanlış: Liste en tanıdık koleksiyon olduğu için ilk akla gelen seçimdir. Ama liste aynı değeri birden çok kez tutar; benzersizliği elle sağlamak gerekir.
  • D yanlış: Kelimeler zaten metin olduğu için ayrı bir yapıya gerek yokmuş gibi görünür. Ama metin, kelimeleri ayrı öğeler olarak tutan bir koleksiyon değildir.
  • E yanlış: Sözlük anahtarları da tekil olduğu için bu seçim işe yarar gibi görünür. Ama gerekçe yanlıştır: benzersizliği sıra değil, anahtarların tekil olması sağlar. Değer tarafı da boşa gider; yalnız üyelik için küme yeterlidir.

Madde 2. Doğru: A. Demetin elemanları değişmedi, içindeki listenin durumu değişti. Demetin değişmez olması, elemanlarına yeni değer atanamayacağı anlamına gelir. record[1] hâlâ aynı listeyi gösterir; o listenin içeriği ise değiştirilebilir.

  • B yanlış: append “sona ekle” diye okunduğunda değer demetin sonuna eklenmiş gibi görünür. Ama append demete değil, demetin içindeki listeye uygulanır.
  • C yanlış: Demetin değiştirilemez olduğunu bilen öğrenci her değişikliğin hata vereceğini bekler. Oysa hata ancak record[1] = ... gibi bir atamada çıkar; burada demetin elemanına yeni değer atanmıyor.
  • D yanlış: Demetin değişmezliği, içindeki listeyi korumak için kopyaladığı izlenimini verir. Oysa demet elemanlarını kopyalamaz; nesnelere referans tutar.
  • E yanlış: Demetin metotları kısıtlı olduğu için elemanlarının da kısıtlı olduğu düşünülebilir. Ama eleman bir listedir; listenin metotları çağrılabilir.

Madde 3. Doğru: D. second = first yeni bir liste oluşturmaz; iki ad aynı liste nesnesini gösterir. Bir addan yapılan değişiklik diğerinden de görülür.

  • A yanlış: Ekleme second adıyla yapıldı, ama iki ad aynı listeyi gösterdiği için iki satır da aynı çıkar.
  • B yanlış: Atama kopya alsaydı böyle olurdu; oysa atama aynı listeye yalnızca ikinci bir ad verir.
  • C yanlış: append listeyi sıfırlamaz; sonuna ekler.
  • E yanlış: Aynı nesneye birden çok ad bağlamak geçerli ve yaygındır.

Madde 4. Doğru: A. Python argüman olarak verilen nesneyi fonksiyona kopyalamaz. Fonksiyon içindeki liste ile dışarıdaki sayilar aynı nesneyi gösterir.

  • B yanlış: Python argümanı kopyalamaz. Bu beklenti, C’deki “fonksiyona değerin kopyası gider” alışkanlığından gelir.
  • C yanlış: Fonksiyon bir şey döndürmediği için None akla gelir. Ama yazdırılan, fonksiyonun dönüş değeri değil, sayilar listesidir.
  • D yanlış: Fonksiyonun dışarıdaki veriye dokunmaması gerektiği sık söylendiği için bunun bir kural olduğu sanılabilir. Böyle bir kısıt yoktur; fonksiyon çağıranın listesini değiştirebilir. Bu yan etkinin istenip istenmediğine fonksiyonu yazan karar verir.
  • E yanlış: Akılda yalnız eklenen değer kalınca bu sonuç seçilebilir. Ama append listeyi sıfırlamaz; sona ekler.

Madde 5. Doğru: E. İçerikleri eşittir ama bunlar iki ayrı liste nesnesidir. == değeri, is kimliği sorgular.

  • A yanlış: Listelerde == eleman eleman karşılaştırır ve eşitlik doğrudur.
  • B yanlış: is her nesne için geçerlidir.
  • C yanlış: İçeriğin eşit olması, iki listenin aynı nesne olduğunu göstermez.
  • D yanlış: Sonuçlar ters yazılmış.

Madde 6. Doğru: C. copy() yeni bir liste nesnesi oluşturur; iki ad artık ayrı nesneleri gösterir.

  • A yanlış: copy anahtar sözcük değildir; ad olarak kullanılabilir.
  • B yanlış: Kopya kaynağın elemanlarıyla başlar; boş değildir.
  • D yanlış: Ekleme copy listesine yapıldı; değişen odur.
  • E yanlış: Bu çıktı copy = original yazılsaydı görülürdü; copy() ise ayrı bir liste oluşturur.

Madde 7. Doğru: E. copy() yalnız bir düzey kopyalar: sığ kopya dış listeyi ayırır, içteki nesneler paylaşılır. copy[0] ile original[0] aynı iç listeyi gösterir.

  • A yanlış: copy() adı tam bir kopya alındığı izlenimini verir. Bu ancak derin kopya alınsaydı doğru olurdu.
  • B yanlış: Kopyanın asıl listeyi korumak için kilitlendiği düşünülebilir. Ama kopyalama içteki listeleri değiştirilemez yapmaz.
  • C yanlış: append çağrısı copy üzerinden yapıldığı için eklemenin dış listeye gittiği sanılabilir. Ama ekleme dış listeye değil, ilk iç listeye yapılır.
  • D yanlış: append yeni bir liste kuruyormuş gibi okunabilir. Ama append iç listeyi sıfırlamaz; sonuna ekler.

Madde 8. Doğru: B. Sözlük üzerinde doğrudan dolaşmak anahtarları verir. (anahtar, değer) çiftleri için .items() gerekir.

  • A yanlış: Her tur tek bir anahtar verir; anahtar ve değer dönüşümlü gelmez.
  • C yanlış: Bu .items() davranışıdır.
  • D yanlış: Sözlük for ile dolaşılabilir.
  • E yanlış: Değerler için .values() yazılmalıdır.

Madde 9. Doğru: D. sorted() yeni bir liste döndürür ve kaynağı değiştirmez.

  • A yanlış: None döndüren list.sort()tur; sorted() yeni liste verir.
  • B yanlış: Dönüş değeri normal bir listedir ve atanabilir.
  • C yanlış: ordered sıralı sonucu tutar.
  • E yanlış: Bu scores.sort() çağrılsaydı olurdu; sorted() yerinde değiştirmez.

Madde 10. Doğru: C. Listeyi yerinde değiştiren metotlar None döndürür. Sıralanmış listeye scores adıyla ulaşılır.

  • A yanlış: Atama geçerlidir; atanan değer Nonedır.
  • B yanlış: Liste sıralanır, ama dönüş değeri liste değildir.
  • D yanlış: Bu sorted(scores) sonucudur.
  • E yanlış: Sıralamanın başarılı olduğunu bildiren bir değer döndürmez.

Tek sayfa özet

  • Her koleksiyonun kendi kullanım alanı var. Bu hafta hepsini aynı ayrıntıda ezberlemek yerine hangisini ne zaman seçeceğinizi öğreniyoruz.
  • Değiştirilebilir nesnelerde iki değişken aynı nesneyi gösterebilir.
  • is iki adın aynı nesneyi gösterip göstermediğini, == değerlerin eşit olup olmadığını sorar.
  • .copy() dış koleksiyonu ayırır; içteki nesneler paylaşılabilir.
  • Sözlüğü anahtar ve değerle birlikte dolaşmak için .items() kullanılır.
  • Sözlük anahtarları hashlenebilir olmalıdır.
  • sorted() yeni liste döndürür; .sort() listeyi yerinde değiştirir.
  • Sözlük programın her yerinden güncellenirse “stok sıfırın altına düşmesin” gibi bir kuralı korumak zorlaşır. İleride sınıf ve metot yazmamızın bir nedeni bu.

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

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

  • list, tuple, dict ve set arasından probleme uygun koleksiyonu seçer.
  • Demetin elemanlarına yeni değer atanamadığını, ama içindeki değiştirilebilir nesnenin değişebildiğini açıklar.
  • b = a sonrasında iki adın aynı nesneyi gösterdiğini tanır ve bir addan yapılan değişikliğin ötekinden de görüleceğini öngörür.
  • is ile == karşılaştırmalarını birbirinden ayırır.
  • copy() ile bağımsız kopya oluşturur ve sığ kopyada neyin ortak kaldığını belirler.
  • Sözlükte .keys(), .values() ve .items() görünümlerini uygun durumda kullanır.
  • sorted() ile .sort() arasındaki farkı dönüş değeri ve listeyi yerinde değiştirme açısından gösterir.
Back to top