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 bölümün kapsamı

NoteSınavda sorulur
  • değişken adının bir nesneye bağlanması
  • nesnenin kimlik, tür ve değer özellikleri
  • aynı nesneye iki referans ve görülen değişiklik
  • is ile == ayrımı
  • küçük tamsayı ve string önbelleklemesinden kural çıkarılamaması
  • nesnenin durumu ve durumun hangi yollarla değiştiği
  • yerinde değiştirme ile yeniden bağlama ayrımı
  • id() değerinin bellek adresiyle ilişkisi
  • çöp toplama (garbage collection) ayrıntıları
  • CPython’ın interning politikasının ayrıntıları

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

Değişken bir kutu değilse nedir?

Başlangıçta değişkeni içine değer konan bir kutu gibi düşünmek işe yarar. İki adın aynı nesneyi gösterdiği ilk örnekte bu model çöker. Yerine kuracağımız model tek cümledir: ad bir nesneye bağlanır. Dersin geri kalanı bu cümlenin üzerine kurulur.

“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.

Sınav provası

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

Madde 1. score = 80 ve ardından score = 90 yazıldığında ne olur?

  • A. score adlı kutunun içindeki 80 değeri 90 ile üzerine yazılır
  • B. score adı önce bir nesneye, sonra başka bir nesneye bağlanır; ilk nesnenin içi değiştirilmez
  • C. İki ayrı score değişkeni oluşur
  • D. Hata verir; bir ada iki kez atama yapılamaz
  • E. 80 değeri bellekten hemen silinir ve score geçersiz olur

Madde 2. Python veri modelinde her nesnenin sahip olduğu üç özellik nedir?

  • A. Durum, davranış ve sorumluluk
  • B. Sınıf, metot ve nitelik
  • C. Kimlik, tür ve değer
  • D. Değer, kopya ve referans
  • E. Ad, adres ve boyut

Madde 3. Bu derste “değer” ile “durum” terimleri nasıl ayrılır?

  • A. “Durum” nesnenin kimliğidir
  • B. İkisi eş anlamlıdır; yalnız farklı kitaplarda farklı yazılır
  • C. “Değer” çalışma anında, “durum” derleme anında belirlenir
  • D. “Değer” Python veri modelinin genel terimidir; “durum” ise OOP’de nesnenin belirli andaki, davranış açısından anlamlı değerlerini anlatan tasarım terimidir
  • E. “Değer” yalnızca sayılar, “durum” yalnızca nesneler için kullanılır

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

product = {"name": "Kalem", "stock": 10}
selected = product
selected["stock"] -= 2

print(product["stock"])
print(product is selected)
  • A. Hata verir; sözlük değeri -= ile güncellenemez
  • B. 10 ve False
  • C. 8 ve False
  • D. 10 ve True
  • E. 8 ve True

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

first = {"name": "Kalem"}
second = {"name": "Kalem"}
third = first

print(first == second)
print(first is second)
print(first is third)
  • A. True, False, True
  • B. True, False, False
  • C. False, False, True
  • D. False, True, True
  • E. True, True, True

Madde 6. is operatörünün önerilen tipik kullanımı hangisidir?

  • A. liste is [] biçiminde boşluk kontrolü
  • B. value is None biçimindeki kimlik kontrolü
  • C. type(x) is int yerine her yerde x is int
  • D. score is 100 biçiminde sayı karşılaştırması
  • E. name is "Ada" biçiminde metin karşılaştırması

Madde 7. a = 5 ve b = 5 iken a is b bazı ortamlarda True verir. Bundan hangi sonuç çıkarılabilir?

  • A. Pyodide Python’ın standart davranışını bozmaktadır
  • B. is operatörü sayılarda == ile aynı işi yapar
  • C. Hiçbir dil kuralı çıkarılamaz; bu, uygulamanın küçük tamsayıları yeniden kullanmasından kaynaklanan bir optimizasyondur
  • D. Küçük sayılarda == kullanmak hatalıdır
  • E. Python’da aynı değerdeki sayılar her zaman aynı nesnedir

Madde 8. Aşağıdaki program neden sorunludur?

product = {"name": "Kalem", "stock": 2}

def sell(product, amount):
    product["stock"] -= amount

sell(product, 5)
print(product)
  • A. amount parametresi product ile aynı adı taşıdığı için çakışma olur
  • B. Sorun yoktur; negatif stok geçerli bir durumdur
  • C. sell fonksiyonu sözlüğü değiştiremez; değişiklik kaybolur
  • D. Stok -3 olur; iş kuralı hiçbir yerde korunmadığı için nesne geçersiz bir duruma düşer
  • E. KeyError yükselir

Madde 9. Sözlükle taşınan bir kaydı sınıfa taşımanın temel gerekçesi nedir?

  • A. Sınıflar veriyi değiştirilemez yaptığı için
  • B. Sınıflar sözlüklerden daha hızlı çalıştığı için
  • C. Sözlükler fonksiyonlara parametre olarak verilemediği için
  • D. Sözlükler yalnızca metin anahtar kabul ettiği için
  • E. Durum ve onu değiştirebilen davranış tek bir ad ve sınır altında toplanır

Madde 10. Aşağıdaki iki program neden farklı davranır?

# A
def add_tag(tags):
    tags.add("oop")

labels = {"python"}
add_tag(labels)
print(labels)

# B
def increase(number):
    number = number + 1

value = 10
increase(value)
print(value)
  • A. A’da küme nesnesi yerinde değiştirilir; B’de parametre adı yeni bir nesneye yeniden bağlanır ve çağıranın bağı etkilenmez
  • B. A’da küme, B’de sayı kullanıldığı için Python birinde referans, diğerinde değer geçirir
  • C. İkisi de aynı davranır; 10 ve {'python'} yazdırır
  • D. A’da global bir değişken kullanıldığı için
  • E. B’de fonksiyon return içermediği için değişiklik kaybolur

Madde 1 — Doğru: B. Atama bir kutunun içeriğini değiştirmez; adın hangi nesneyi gösterdiğini değiştirir.

  • A yanlış: Kutu modeli burada yanıltır; int nesneleri değiştirilemez ve içleri güncellenmez.
  • C yanlış: Tek bir ad vardır; yalnız bağlandığı nesne değişir.
  • D yanlış: Yeniden atama geçerli ve olağandır.
  • E yanlış: Ad her zaman geçerli bir nesneyi gösterir; eski nesnenin akıbeti ayrı bir konudur.

Madde 2 — Doğru: C. Tür desteklenen işlemleri ve değerin değişip değişemeyeceğini belirler; kimlik nesneyi ayırt eder.

  • A yanlış: Bunlar OOP tasarım terimleridir; veri modelinin üç özelliği değildir.
  • B yanlış: Bunlar sınıf tasarımının parçalarıdır; her nesnenin tanımı değildir.
  • D yanlış: Kopya ve referans işlem biçimleridir; nesnenin özellikleri değildir.
  • E yanlış: Ad nesnenin değil bağın parçasıdır; adres ve boyut dil sözleşmesi değildir.

Madde 3 — Doğru: D. Mutable bir nesnenin değeri değişince çoğu zaman “durumu değişti” deriz. İki terim ilişkilidir ama aynı düzlemde değildir.

  • A yanlış: Kimlik nesne yaşadığı sürece sabittir; durum değişebilir.
  • B yanlış: Biri dil başvurusunun, diğeri tasarımın terimidir.
  • C yanlış: Python’da böyle bir derleme anı ayrımı yoktur.
  • E yanlış: Böyle bir tür ayrımı yoktur.

Madde 4 — Doğru: E. selected = product yeni bir sözlük oluşturmaz. Aynı nesneye iki ad üzerinden erişilir; biri üzerinden yapılan değişiklik diğerinden görülür.

  • A yanlış: Bu yazım selected["stock"] = selected["stock"] - 2 ile aynıdır ve geçerlidir.
  • B yanlış: Atama kopya üretmez; iki ad aynı nesneyi gösterir.
  • C yanlış: is aynı nesne için True verir.
  • D yanlış: Aynı nesne değiştirildiği için product da yeni değeri gösterir.

Madde 5 — Doğru: A. first ve second eşit içerikli ama ayrı nesnelerdir. third ise first ile aynı nesnedir.

  • B yanlış: third = first aynı nesneye ikinci bir ad bağlar.
  • C yanlış: Sözlüklerde == anahtar–değer karşılaştırması yapar ve eşitlik doğrudur.
  • D yanlış: İlk iki sonuç ters yazılmış.
  • E yanlış: Eşit içerik aynı nesne olmayı gerektirmez.

Madde 6 — Doğru: B. None tekil bir nesnedir; kimlik kontrolü tam olarak bu durum için uygundur.

  • A yanlış: Her [] yeni bir nesne üretir; bu karşılaştırma hep yanlış sonuç verir.
  • C yanlış: Bu bir değeri bir sınıfla karşılaştırır ve anlamsızdır.
  • D yanlış: Sayı eşitliği için == kullanılır.
  • E yanlış: Metin eşitliği için == kullanılır; is sonucu uygulama ayrıntısına bağlı olabilir.

Madde 7 — Doğru: C. Önbellekleme davranışı CPython, Pyodide veya başka bir uygulamada farklı görünebilir. Değer sorusu için == kullanılmalıdır.

  • A yanlış: Önbellekleme zaten dil sözleşmesinin dışında bırakılmıştır.
  • B yanlış: Farklı sorulardır; sonuçların rastlantısal olarak örtüşmesi bunu değiştirmez.
  • D yanlış: Tam tersine, değer karşılaştırması için güvenilir olan ==dır.
  • E yanlış: int("1000") ile üretilen iki değer aynı nesne olmayabilir.

Madde 8 — Doğru: D. Program hata vermez ve çalışır. Eksik olan, durumun geçerli kalmasını sağlayan doğrulamadır.

  • A yanlış: Adlar farklıdır ve çakışma yoktur.
  • B yanlış: Stokun negatif olması iş kuralına aykırıdır; sessizce kabul edilmesi asıl sorundur.
  • C yanlış: Sözlük paylaşılan bir nesnedir; değişiklik çağırana da yansır.
  • E yanlış: stock anahtarı mevcuttur.

Madde 9 — Doğru: E. Sistem büyüdükçe hangi anahtarların bulunması gerektiği ve hangi fonksiyonların kaydı değiştirebildiği dağılır. Sınıf bu sınırı çizer.

  • A yanlış: Örnek nitelikleri değiştirilebilir; korunan şey geçerlilik kuralıdır.
  • B yanlış: Gerekçe başarım değil, sorumluluk sınırıdır.
  • C yanlış: Verilebilir; zaten örnekte verilmektedir.
  • D yanlış: Sözlükler hashlenebilir her türü anahtar olarak kabul eder.

Madde 10 — Doğru: A. Yerinde değiştirme paylaşılan nesneyi etkiler. Yeniden bağlama yalnız fonksiyonun kendi adını etkiler. A {'python', 'oop'}, B 10 yazdırır.

  • B yanlış: Aktarım biçimi her iki durumda da aynıdır; fark yapılan işlemdedir.
  • C yanlış: A’daki add çağrısı kümeyi gerçekten değiştirir.
  • D yanlış: labels parametreyle geçirilir; global bildirimi yoktur.
  • E yanlış: return olsa bile atama yapılmadıkça çağıranın adı değişmezdi; asıl neden yeniden bağlamadır.

Tek sayfa özet

  • 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.

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

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

  • Değişken adının bir nesneye bağlandığını, kutu olmadığını açıklar.
  • Bir nesnenin kimlik, tür ve değer özelliklerini ayırır.
  • Aynı nesneye iki referans olduğunda bir addan yapılan değişikliğin diğerinden görüldüğünü gösterir.
  • is ile == sorularını ayırır ve is kullanımını kimlik sorusuyla sınırlar.
  • Küçük tamsayı ve string önbelleklemesinden dil kuralı çıkarılamayacağını açıklar.
  • Nesnenin durumunu tanımlar ve durumun hangi yollarla değişebileceğini sorgular.
  • Mutable nesnede yerinde değişiklik ile immutable nesnede yeniden bağlamayı ayırır.
Back to top