Ek: Nesne durumunu izleme
Nesne durumunu izleme çalışmaları
Programlama Temelleri’nde kodu satır satır izleyip değişkenlerin değerini bir tabloya yazmıştınız. Bu sayfada aynı yöntemi nesnelere uyguluyorsunuz. Bu kez yalnız çıktıyı bulmakla kalmaz, hangi nesnelerin var olduğunu, hangi adın hangi nesneye bağlı olduğunu ve her nesnenin durumunun satır satır nasıl değiştiğini tabloda adım adım izlersiniz.
Her soruda önce tabloyu kodu çalıştırmadan doldurun. Tahmininiz bitince kodu Python’da, isterseniz Python Tutor sitesinde de çalıştırıp kontrol edin. Python Tutor tahmininizi kontrol etmek içindir. Tabloyu sizin yerinize doldurmasın diye onu en başta açmayın.
Kullanacağınız izleme tablosu
Her önemli satırdan sonra tabloya aşağıdaki biçimde bir satır ekleyin. N1, N2 gibi nesne kimlikleri, Python’ın id() ile verdiği gerçek sayılar değildir. Çizimde nesneleri birbirinden ayırmak için sizin koyduğunuz etiketlerdir.
| Satır | Var olan nesneler ve durumları | Ad → nesne bağları | Ne değişti? |
|---|---|---|---|
| 1 | |||
| 2 | |||
| … |
6. hafta: kimlik, referans ve değiştirilebilirlik
Çalışma 1: İki ad, tek liste
a = [10, 20]
b = a
b.append(30)
c = [10, 20, 30]Tabloyu 1., 2., 3. ve 4. satırlardan sonra doldurun.
Cevaplamanız gerekenler:
- Kaç ayrı liste nesnesi vardır?
avebaynı nesneyi mi gösterir?a == cvea is csonuçları ne olur?- Üçüncü satırdan sonra
aneden değişmiş görünür?
Üçüncü satıra kadar tek liste vardır; a ve b aynı listeye bağlıdır. Dördüncü satır, içeriği aynı ama kimliği farklı ikinci bir liste oluşturur. Son durumda a == c True, a is c False olur.
Çalışma 2: Adı yeniden bağlamak nesneyi değiştirmez
x = 100
y = x
x = 101
z = yHer satırdan sonra hangi int değerlerine ulaşılabildiğini ve x, y, z adlarının hangi değere bağlı olduğunu yazın.
Cevaplamanız gerekenler:
x = 101satırı 100 değerli nesneyi değiştirir mi?- Son durumda
yvezneden 100’e bağlıdır? - Bu örneğin liste örneğinden farkı nedir?
x = 101, x adını yeni bir değere bağlar. y hâlâ 100’e bağlıdır; z = y satırıyla z de 100’e bağlanır. int değiştirilemez (immutable) olduğu için burada, listedeki append() gibi nesneyi yerinde değiştiren bir işlem yoktur.
Çalışma 3: Fonksiyon çağrısında aynı nesne
def etiket_ekle(etiketler):
etiketler.add("oop")
etiketler = {"python"}
yedek_ad = etiketler
etiket_ekle(etiketler)Fonksiyon çağrısı sırasında etiketler parametresinin hangi nesneye bağlandığını da tabloya ekleyin.
Cevaplamanız gerekenler:
- Fonksiyon yeni bir küme kopyası mı oluşturur?
- Çağrıdan sonra
yedek_adyazdırılsa ne görülür? - Fonksiyon içinde
etiketler = {"oop"}yazılsaydı sonuç neden farklı olurdu?
Çağrı sırasında parametre adı da aynı küme nesnesine bağlanır. add() nesneyi yerinde değiştirdiği için dışarıdaki iki ad da değişmiş kümeyi gösterir. Parametreyi yeni bir kümeye bağlamak ise yalnız fonksiyonun içindeki adı etkiler; çağıran koddaki adlar eski kümeye bağlı kalır.
9. hafta: nesne durumu ve kompozisyon
Çalışma 4: İki sepet, paylaşılan ürün
class Urun:
def __init__(self, ad, fiyat):
self.ad = ad
self.fiyat = fiyat
class Sepet:
def __init__(self):
self.urunler = []
urun = Urun("Kalem", 20)
s1 = Sepet()
s2 = Sepet()
s1.urunler.append(urun)
s2.urunler.append(urun)
urun.fiyat = 25Aşağıdaki nesneleri ayrı satırlarda izleyin: Urun, s1 sepeti, s2 sepeti ve iki sepetin içindeki liste nesneleri.
Cevaplamanız gerekenler:
- Toplam kaç
Urunnesnesi vardır? - İki listenin elemanı aynı
Urunnesnesi midir? - Son satırdan sonra her iki sepetten bakıldığında fiyat neden 25 görünür?
- Ürünün sepete eklendiği andaki fiyatı saklamak isteseydiniz tasarımda neyi değiştirmeniz gerekirdi?
Tek bir Urun nesnesi vardır ve iki ayrı sepet listesi de bu ürüne referans tutar. Ürünün durumu değişince iki sepet de aynı nesnenin güncel fiyatını görür. Geçmiş fiyatı saklamak için sepette ürün referansının yanına o anki fiyatı yazabilir ya da ürünü ve fiyatı birlikte tutan bir satır nesnesi kullanabilirsiniz.
Çalışma 5: Kompozisyon ve delegation
class Adres:
def __init__(self, sehir):
self.sehir = sehir
class Musteri:
def __init__(self, ad, adres):
self.ad = ad
self.adres = adres
def teslimat_sehri(self):
return self.adres.sehir
adres = Adres("Samsun")
musteri = Musteri("Ada", adres)
yedek = adres
adres.sehir = "Ordu"İzleme tablosunda Adres ve Musteri nesnelerini, Musteri.adres niteliğinin hangi nesneye referans verdiğini ve yedek adını gösterin.
Cevaplamanız gerekenler:
- Son durumda
musteri.teslimat_sehri()ne döndürür? musteri.adresileyedekaynı nesneyi mi gösterir?Musterinesnesi birAdresyerine yalnız"Samsun"string’ini tutsaydı sonuç nasıl değişirdi?
Musteri.adres ve yedek aynı Adres nesnesine bağlıdır. Bu nesnenin sehir niteliği "Ordu" olunca teslimat_sehri() de "Ordu" döndürür, çünkü metot işi adres nesnesine devreder (delegation).
Çalışma 6: İç listeyi dışarıya vermek
class NotDefteri:
def __init__(self):
self._notlar = [70, 80]
@property
def notlar(self):
return self._notlar
n = NotDefteri()
dis_liste = n.notlar
dis_liste.append(0)Tabloda NotDefteri nesnesi ile _notlar liste nesnesini ayrı gösterin.
Cevaplamanız gerekenler:
dis_listeyeni bir liste midir?- Son durumda
n.notlarne döndürür? - Bu durum kapsülleme açısından neden risklidir?
- Property içinde
return tuple(self._notlar)yazılsaydıdis_listeneye bağlanırdı, onu değiştirebilir miydiniz?
Property iç listenin kendisini döndürdüğü için dis_liste aynı listeye ikinci bir referanstır. Dışarıdan çağrılan append(), sınıfın metotlarından geçmeden iç durumu değiştirir. Property bir tuple kopyası döndürseydi dış kod iç listeyi bu yoldan yerinde değiştiremezdi.
Son çalışma: iki tabloyu karşılaştırın
Çalışma 1 ile Çalışma 4’ü yan yana koyun. Birinde paylaşılan nesne bir liste, ötekinde bir Urun nesnesidir. Şu cümleyi kendi sözlerinizle tamamlayın:
Aliasing yalnız listelere özgü değildir; …
Varmanız beklenen fikir: Aynı mutable nesneye birden çok referans varsa, nesneyi bunlardan biriyle değiştirdiğinizde değişiklik ötekilerden de görünür.