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ı
NoteSınav dışı (bilgi amaçlı)
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.
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?
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 =5b =5print(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 sorusuprint(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 = firstthird = {"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"]:raiseValueError("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
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?
# Adef add_tag(tags): tags.add("oop")labels = {"python"}add_tag(labels)print(labels)# Bdef increase(number): number = number +1value =10increase(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
TipCevaplar ve gerekçeler
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.