Terminal ekranına basit bir print(0.1 + 0.2) yazdığında ne görmeyi beklersin? İlkokul matematiği sana sonucun tartışmasız 0.3 olduğunu söyler. Ancak Python enter tuşuna bastığın anda suratına şunu çarpar: 0.30000000000000004! Bir süper bilgisayarın veya yapay zeka çalıştıran modern bir işlemcinin iki minik sayıyı toplayamayacak kadar "cahil" olduğunu mu sanıyorsun? Kesinlikle hayır; bu bir yazılım hatası değil, silikon transistörlerin ikili (binary) dünyası ile insan zihninin ondalık tabanı arasındaki kaçınılmaz kuantum benzeri fiziksel çatışmadır!
Kod yazarken her gün kullandığımız String (Metin), Integer (Tam Sayı), Float (Kayan Noktalı Sayı) ve Boolean (Mantıksal Doğru/Yanlış) tipleri, arka planda işletim sisteminin bellek yönetimini, CPU kayıtçılarını (registers) ve transistör mantık kapılarını doğrudan kontrol eder. C dilinde sınırları aşınca çöken tamsayılar Python'da nasıl gökyüzüne kadar uzanır? Metinler RAM'de neden sabitlenmiş birer taşa dönüşür? Bu rehberde; yüzeysel tanımları bir kenara bırakıyoruz. IEEE 754 standardının kayan nokta fiziğinden Python'ın sınırsız tamsayı (Bignum) algoritmasına, Unicode karakter tablolarından 1-bitlik mantık kapılarına kadar temel veri tiplerinin donanım düzeyindeki anatomisine iniyoruz!
1. Integer (int): Sınırları Yıkan "Bignum" Aritmetiği
C, C++ veya Java gibi geleneksel dillerde bir tamsayı tanımladığında işlemci sana 32-bit (en fazla 2.14 milyar) ya da 64-bit (en fazla 9 kentilyon) sınır koyar. Bu sınırın üzerine tek bir 1 eklersen Aritmetik Taşma (Integer Overflow) yaşanır; sayı bir anda eksi milyarlara fırlar ve roket fırlatma sistemlerini bile havada patlatabilir (ünlü Ariane 5 roket kazası gibi).
Python'da ise 2 ** 1000 yazsan dahi Python istifini bozmaz, yüzlerce basamaklı devasa sayıyı milisaniyede hesaplar. Peki Python bunu nasıl başarır?
- Dinamik Sayısal Dizi (Bignum) Fiziği: Python 3'te tamsayılar donanımın 32-bitlik veya 64-bitlik tek bir işlemci kaydına hapsedilmez. Sayı büyüdükçe CPython arka planda 30-bitlik parçalardan (digit) oluşan dinamik bir C dizisi açar.
- Bellek Ne Kadar Büyürse Sayı O Kadar Büyür: Python'da bir tamsayının tavan sınırı CPU mimarisi değil, bilgisayarındaki fiziksel RAM kapasitesidir. İster yüz basamaklı bir RSA şifreleme anahtarı, ister trilyon basamaklı bir pi sayısı hesapla; Python belleği dilimleyerek sayıyı güvenle saklar.
[GELENEKSEL DİLLER vs. PYTHON INTEGER MİMARİSİ]
C / Java (Sabit Donanım Kaydı) : [64-bit Kutu] ---> Limit Aşılırsa: OVERFLOW PATLAMASI!
Python Bignum (Dinamik C Dizisi): [30-bit Blok] + [30-bit Blok] + [30-bit Blok]... (RAM Yettikçe Sonsuz)
0.1 ile 0.2'nin toplamının 0.3 çıkmaması bir Python hatası değildir; silikon transistörlerin ikili (binary) dünyası ile insan zihninin ondalık tabanı arasındaki kaçınılmaz kuantum çatışmasıdır.
2. Float: "0.1 + 0.2 != 0.3" Çelişkisi ve IEEE 754 Standardı
Yazılıma yeni başlayanların şaşkınlıkla karşıladığı o ünlü 0.30000000000000004 sonucunun arkasında küresel IEEE 754 Kayan Nokta (Floating Point) standardı yatar.
İnsan beyni 10'luk tabanda düşünür. 10 sayısının asal çarpanları 2 ve 5 olduğu için; 1/2 (0.5) veya 1/5 (0.2) sayıları ondalık tabanda sonlu ve nettir. Ancak bilgisayarlar yalnızca 2'lik tabanda (0 ve 1) yaşar! 2'lik tabanda bir sayının sonlu olabilmesi için paydasının 2'nin kuvveti olması gerekir (1/2, 1/4, 1/8 gibi).
10'luk tabandaki 0.1 sayısı ikili tabana çevrilmeye çalışıldığında ortaya sonsuz bir devirli sayı çıkar: 0.00011001100110011.... İşlemci bu sonsuzluğu 64-bitlik Float kaydına sığdırmak için 53. bitten sonrasını yuvarlayarak (keserek) kaydeder. İşte 0.1 ile 0.2 toplandığında bu minik yuvarlama artıklarının birikmesi sonucu o fazladan ...0004 ortaya çıkar!
# Hassas Finansal Hesaplarda Float Kullanmayın!
a = 0.1 + 0.2
print(a == 0.3) # False!
# ÇÖZÜM: Kuruşuna kadar kesin hesap için 'decimal' modülü:
from decimal import Decimal
para_1 = Decimal('0.1')
para_2 = Decimal('0.2')
print(para_1 + para_2 == Decimal('0.3')) # True!
3. String (str): Unicode Evreni ve Bellekte İmmutability Zırhı
Python'da bir metin (string), sıradan bir karakter yığını değildir. Her bir karakter, dünya üzerindeki tüm alfabeleri, antik hiyeroglifleri ve hatta emojileri temsil edebilen Unicode (UTF-8 / UCS-4) standardıyla kodlanır.
String veri tipinin en kritik mühendislik özelliği Değiştirilemez (Immutable) olmasıdır. Bellekte bir metin oluşturulduğunda, onun harfleri doğrudan yerinde değiştirilemez:
metin = "Python"
# metin[0] = "J" # HATA! TypeError: 'str' object does not support item assignment
Peki Python neden metinleri bu kadar katı bir zırhla korur? Cevap: Sistem Güvenliği ve Hash Optimizasyonu. Python'ın sözlükleri (dictionary) ve küme (set) yapıları, arama işlemlerini sıfır gecikmeyle (O(1) karmaşıklıkla) yapmak için anahtarların hash değerine güvenir. Eğer bir metin yerinde değiştirilebilseydi, sözlük indeksleri parçalanır ve bellek adresleme mimarisi çökerdi!
4. Boolean (bool): 1-Bit Mantığın Integer Mirası
Python'da True ve False mantıksal değerleri, sadece bir şartın doğru ya da yanlış olduğunu belirtmez; dilin kökeninde doğrudan birer tamsayıdır!
Python kaynak koduna (C katmanına) indiğinizde bool sınıfının doğrudan int sınıfından türediğini (subclass) görürsünüz. Yani teknik olarak:
- True: Aslında arka planda sayısal değeri
1olan bir int nesnesidir. - False: Aslında arka planda sayısal değeri
0olan bir int nesnesidir.
# Boolean değerlerin matematiksel doğası
print(True + True) # Çıktı: 2
print(True * 50) # Çıktı: 50
print(False - 5) # Çıktı: -5
print(isinstance(True, int)) # True! (bool, int'in öz çocuğudur)
Bu durum kod yazarken sana büyük bir güç sağlar: Örneğin bir listedeki şartı sağlayan kaç eleman olduğunu saymak için döngü kurup sayaç artırmak yerine doğrudan sum([x > 10 for x in liste]) yazabilirsin. Mantıksal doğrular otomatik olarak 1'e dönüşüp toplanır!
5. Bellek Tüketimi ve Tip Dönüşümleri (Type Casting) Kıyas Tablosu
Her veri tipi, taşıdığı metaveri ve yönetim kabuğuna göre Heap bellekte farklı bir ayak izi bırakır. Python'ın sys.getsizeof() fonksiyonu ile ölçülen saf bellek maliyetleri:
| Veri Tipi | Python Sınıfı | Boş / Temel Boyut (RAM) | Değiştirilebilirlik | Tip Dönüşüm Sözdizimi |
|---|---|---|---|---|
| Integer | int |
28 Bayt (0 için 24 Bayt) | Immutable (Değiştirilemez) | int("42") -> 42 |
| Float | float |
24 Bayt | Immutable (Değiştirilemez) | float("3.14") -> 3.14 |
| String | str |
49 Bayt + Karakter başına (1-4 B) | Immutable (Değiştirilemez) | str(100) -> "100" |
| Boolean | bool |
28 Bayt (int mirasçısı) | Immutable (Değiştirilemez) | bool(1) -> True |
Python'da bir şart bloğuna (if) sadece bool değişkenleri değil, herhangi bir nesneyi sokabilirsin. Python şu değerleri otomatik olarak False (Falsy) kabul eder: Sayısal sıfırlar (0, 0.0), boş diziler ve koleksiyonlar ("", [], {}, ()) ve None. Bunların dışındaki tüm nesneler doğrudan True (Truthy) olarak değerlendirilir. Bu mekanizma kodları gereksiz uzunluktan kurtaran Pythonic zarafetin temelidir.
Veri tipleri sadece değişken tanımlamak için kullanılan sentaks etiketleri değildir. Bir sayının tam mı ondalıklı mı olduğu, bir metnin bellekte nasıl kilitlendiği ve mantıksal bir şartın işlemci düzeyinde 0 veya 1'e nasıl indirgendiği; yazdığın yazılımın çalışma hızını, finansal doğruluğunu ve RAM tüketimini belirleyen temel fizik kuralıdır.
