Python’da nesne zihinsel modeli: kimlik, değer, durum ve referans

Bu haftadan itibaren dersin ana konusu nesne tabanlı programlamadır. Ancak hemen class sözdizimine atlamayacağız. Önce Python’da bir nesnenin ne olduğunu, değişken adlarının nesnelerle nasıl ilişki kurduğunu ve aynı nesnenin birden fazla yerden görülebilmesinin ne anlama geldiğini anlamamız gerekir.

Bu hafta neleri yapabilmelisiniz?

  • Nesne, referans, kimlik, tür, değer ve durum kavramlarını birbirinden ayırabilmeli,
  • Bir değişken adının nesnenin kendisi olmadığını açıklayabilmeli,
  • id(), type(), is ve == kullanım amaçlarını ayırabilmeli,
  • Küçük tamsayı/string gibi nesnelerde uygulama içi önbelleklemenin is sonuçlarını şaşırtabileceğini açıklayabilmeli,
  • Değiştirilebilir nesnelerde ortak referansın etkisini tahmin edebilmeli,
  • Fonksiyon parametrelerinin nesnelere erişim sağladığını gözlemleyebilmeli,
  • Bir problemde “veri” ile “davranış”ın neden birlikte düşünülebileceğini açıklayabilmelisiniz.

“Değişken kutudur” modeli neden yetersiz kalır?

Başlangıç programlamasında değişkeni bir kutu gibi düşünmek işe yarayabilir. Python’da nesne ilişkilerini anlamaya başladığımızda daha doğru bir model gerekir:

Değişken adı, bir nesneye bağlanır.

score = 80

ifadesinde score adı, değeri 80 olan bir int nesnesine bağlanır. Daha sonra:

score = 90

yazdığımızda “80 nesnesinin içini 90 yapmak” zorunda değiliz; score adı başka bir nesneye yeniden bağlanır.

Python veri modelinde: kimlik, tür ve değer

Python dil başvurusunda her nesnenin kimliği (identity), türü (type) ve değeri (value) olduğu belirtilir. Tür, nesnenin desteklediği işlemleri ve değerinin değişip değişemeyeceği gibi özellikleri belirler.

Python veri modelinde bir nesnenin kimlik, tür ve değer özelliklerini; OOP bağlamında değişebilen değerlerin durum olarak yorumlanmasını gösteren diyagram.

Nesnenin kimlik, tür ve değeri

Burada:

  • type(scores) nesnenin türünü,
  • id(scores) çalışma süresi boyunca o nesneyi ayırt eden kimlik değerini,
  • scores ise nesnenin değerini/içeriğini görmemize yardımcı olur.
Important“Değer” ile “durum” aynı terim değildir

Değer (value) Python veri modelinin genel terimidir. Durum (state) ise OOP bağlamında, bir nesnenin belirli andaki davranış açısından anlamlı değerlerini anlatmak için kullandığımız tasarım terimidir. Mutable bir nesnenin değeri değiştiğinde çoğu zaman “nesnenin durumu değişti” deriz. Bu iki kavramı birbirine karıştırmadan ilişkilendirin.

Noteid() değerini bellek adresi diye ezberlemeyin

Bazı Python uygulamalarında id() ile bellek adresi arasında yakın ilişki olabilir; ancak dil düzeyinde güvenmemiz gereken sözleşme bu değildir. Biz id() değerini yalnızca iki referansın aynı nesneyi gösterip göstermediğini gözlemlemek için kullanacağız. Bu amaç için doğrudan is daha okunaklıdır.

Aynı nesneye iki referans

product ve selected iki farklı sözlük değildir. Aynı sözlük nesnesine iki farklı ad üzerinden erişiyoruz.

Kimlik ve eşitlik aynı soru değildir

  • first == second: değer/eşitlik bakımından eşit mi?
  • first is second: aynı nesne mi?
  • first is third: aynı nesne mi?

is işlecinın nesne kimliğini, çift eşittirin ise değer eşitliğini sorguladığını gösteren diyagram.

Kimlik ve eşitlik
Importantis değer karşılaştırma operatörü değildir

Sayı veya string değerlerini karşılaştırmak için genel olarak == kullanın. is, nesne kimliği sorusudur ve özellikle None kontrolünde (value is None) yaygın biçimde kullanılır.

Küçük tamsayı ve string “interning” tuzağı

Öğrenciler genellikle şu deneyi yapar:

a = 5
b = 5
print(a is b)

ve bazı ortamlarda True görür. Bunun nedeni Python uygulamasının küçük tamsayıları veya bazı stringleri yeniden kullanabilmesidir (interning/caching). Bu bir uygulama optimizasyonudur; “aynı değerdeki sayılar aynı nesnedir” biçiminde bir dil kuralı değildir.

x = int("1000")
y = int("1000")
print(x == y)  # güvenilir değer sorusu
print(x is y)  # uygulama ayrıntısına bağlı olabilir
Warningis deneylerinden yanlış dil kuralı çıkarmayın

CPython, Pyodide veya başka bir Python uygulamasında önbellekleme davranışı farklı görünebilir. Bu yüzden sayılar ve stringlerde değer karşılaştırması için == kullanın; is sonucunu uygulamanın nesne yeniden kullanım politikasını kanıtlamak için kullanmayın.

Nesnenin durumu

OOP bağlamında bir nesnenin belirli bir andaki, davranış açısından anlamlı değerlerini onun durumu (state) olarak düşünürüz. Özellikle mutable nesnelerde bu durum zamanla değişebilir.

{"name": "Kalem", "stock": 8}

örneğinde stock değeri durumun bir parçasıdır. Stok 8’den 7’ye inerse nesnenin durumu değişir; kimliği ve türü aynı kalabilir.

OOP’de temel soru şudur:

Bu durumun hangi yollarla değişmesine izin veriyoruz?

Davranış neden verinin yanında olmalı?

Program çalışır ama stock = -3 olur. İş kuralı kaybolmuştur.

Fonksiyonu doğrulamayla iyileştirebiliriz:

Sistem büyüdükçe product sözlüğünün hangi anahtarlara sahip olması gerektiği ve hangi fonksiyonların onu değiştirebildiği dağınık hâle gelebilir. Sınıf, durum ve davranışa ortak bir ad ve sınır vermemizi sağlar.

Fonksiyon parametresi nesneyi kopyalamaz

Fonksiyon, aynı küme nesnesine erişir. Buna karşılık immutable bir nesnede yeniden bağlama çağıranı değiştirmez:

Alıştırma — Aynı mı, eşit mi?

Ardından c.append(3) ekleyip a, b, c değerlerini tekrar yazdırın.

Alıştırma — Referans diyagramı

first = {"balance": 100}
second = first
third = {"balance": 100}

Üç değişken adı ve kaç ayrı sözlük nesnesi olduğunu gösteren bir diyagram çizin. Ardından second["balance"] += 50 sonrası hangi adlar üzerinden 150 görüleceğini açıklayın.

Alıştırma — Geçersiz durumu engelle

if amount > account["balance"]:
    raise ValueError("Yetersiz bakiye")

Küçük üretim görevi — Prosedürel hesabı incele

account = {
    "owner": "Ada",
    "balance": 500,
}

Para yatırma, para çekme ve bakiye sorgulama fonksiyonlarını yazın. Geçersiz tutarlarda ValueError üretin ve başarısız işlemden sonra sözlüğün değişmediğini doğrulayın.

Çalışır kod teslimi: Normal para çekme, yetersiz bakiye ve negatif tutar senaryolarını çalıştırın; en az üç assert ile bakiyeyi doğrulayın.

Sonunda şu soruyu cevaplayın:

Bu üç fonksiyonu ve hesabın verisini tek bir kavram altında toplamak istersek ne kazanırız?

Bu sorunun cevabı gelecek haftanın class Account tasarımına geçişidir.

Kendinizi kontrol edin

  1. Değişken adı ile nesne arasındaki ilişki nedir?
  2. Python veri modeline göre nesnenin üç temel özelliği nedir?
  3. OOP’deki “durum” ile veri modelindeki “değer” nasıl ilişkilidir?
  4. is hangi soruyu sorar?
  5. Küçük tamsayılarda a is b neden bazen True olabilir ve neden buna güvenmemeliyiz?
  6. Aynı mutable nesneye iki referans varsa birinden değişiklik yapılınca diğeri neden yeni durumu görür?

Bu haftadan akılda kalması gerekenler

  • Python veri modelinde her nesnenin kimliği, türü ve değeri vardır.
  • OOP’de mutable nesnenin zaman içinde değişen anlamlı değerlerini durum olarak yorumlarız.
  • Değişken adı nesne değildir; nesneye bağlanır.
  • == eşitlik, is kimlik sorusudur.
  • Küçük tamsayı/string önbelleklemesi uygulama ayrıntısıdır; değer karşılaştırmasını == ile yapın.
  • Aynı mutable nesneye birden fazla referans olabilir.
  • OOP’nin motivasyonlarından biri, durumu ve onu değiştiren kurallı davranışları aynı sorumluluk sınırında toplamaktır.
Back to top