bool ve None: Truthiness'in Felsefesi ve Sentinel Değer Sanatı
Python'da `True` aslında `int`'in alt sınıfı (`True + 1 == 2`!). Her tip 'doğru/yanlış' bağlamında değerlendirilebilir — buna 'truthiness' denir. None ise 'değer yok' anlamına gelen tek-elemanlı bir sentinel. Bu derste: bool gerçek doğası, falsy değerler tablosu, `is None` vs `== None`, Optional type hint, default arg sentinel pattern, ve günlük kodda en sık karşına çıkan 'küçük' detayların derinliği.
Şükrü Yusuf KAYA
20 dakikalık okuma
Başlangıç🤯 Bu ders küçük gibi görünür ama her gün kullanırsın
True/False ve None — her Python kodunda. Ama detaylar bilinmediğinde sürpriz: True + 1 == 2, [] truthy mi falsy mi (falsy), None is None vs == None — birinin kullanılmaması var. Bu derste 'her gün karşına çıkan' kavramların hayatın derinliğini öğreneceksin.
bool — int'in alt sınıfı (gerçekten!)#
Python'da özel bir tip ama altta . Yani:
boolint>>> isinstance(True, int) True >>> type(True) <class 'bool'> >>> bool.__bases__ (<class 'int'>,) # bool, int'ten miras alıyor >>> True + 1 2 >>> True * 5 5 >>> False * 100 0 >>> sum([True, False, True, True]) 3 # True'lar 1, False'lar 0
Bu özellik kasıtlı. Eski Python'larda (2.0 öncesi) bool yoktu — ve kullanılıyordu. Sonra Python 2.3'te eklendi ama geriye uyumluluk için 'in alt sınıfı yapıldı.
01boolintPratik faydası: ile bool listesindeki True'ları sayabilirsin.
sum()data = [10, 20, 30, 40, 50] # Kaç elemanı 25'ten büyük? count = sum(1 for x in data if x > 25) # geleneksel count = sum(x > 25 for x in data) # daha kısa, bool aritmetiği print(count) # 3
Bu pratik özellik veri analizinde sıkça kullanılır — boolean kolonlarda da çalışıyor.
pandas.DataFrame.sum()🚨 Bool olduğunu düşündüğün şey aslında int gibi davranır. Kötü patterns:
# 🚫 (çalışıyor ama yanıltıcı) score = True + 5 # 6 done = False / 1 # 0.0 # ✅ score = 5 + (1 if condition else 0)
Truthiness — her şey "doğru veya yanlış" olabilir#
Python'da yazdığında herhangi bir tip olabilir. Python ona "doğru mu yanlış mı?" diye soruyor. Bu kavrama truthiness (doğruluk) deniyor.
if x:xFalsy (yanlış değerlendirilen) değerler#
Sadece şu değerler falsy:
# Tüm falsy değerler: False # bool None # NoneType 0 # int 0.0 # float 0j # complex "" # boş string [] # boş list () # boş tuple {} # boş dict set() # boş set range(0) # boş range b"" # boş bytes bytearray() # boş bytearray
Diğer her şey truthy. Bu liste önemli; ezberle:
bool(False) # False bool(None) # False bool(0) # False bool(0.0) # False bool("") # False bool([]) # False bool({}) # False bool(True) # True bool(1) # True bool(-1) # True (sıfır olmayan her int truthy) bool(0.0001) # True bool("0") # True! (boş olmayan string truthy) bool("False") # True! (içerik "False" yazısı, boş değil) bool([0]) # True! (içinde 0 var ama liste boş değil) bool([False]) # True! bool({0: 0}) # True! (dict boş değil)
🎯 Yıldızlı tuzaklar:
- truthy çünkü boş değil!
"0" - truthy çünkü içeriği "F-a-l-s-e" karakterleri.
"False" - truthy çünkü liste boş değil (içeriğine bakmaz, varlığa bakar).
[0]
Bunlar JavaScript ile farklı ( JS'de truthy, da truthy ama JS'de ).
"0""false"!"" === trueTruthiness'i Pythonic kullanmak#
Truthiness Python'a "kısa, anlamlı" if statement'ları yazmana imkan veriyor:
# Liste boş mu kontrol etme items = [] # 🚫 Java aksanı if len(items) == 0: print("Boş") # 🚫 Daha da kötü if items == []: print("Boş") # ✅ Pythonic if not items: print("Boş") # String boş mu name = "" # 🚫 if len(name) == 0: do_something() # ✅ if not name: do_something() # Default değer (or kısa-circuit) display_name = user.name or "Anonim" # name boşsa "Anonim" # Listenin ilk truthy elemanı first_truthy = next((x for x in items if x), None)
Ama dikkat — bazı durumlarda explicit kontrol şart#
def process(value): # 🚫 Hatalı: 0, "", [], None hepsi falsy ama anlamları farklı if not value: return "Eksik veri" # value=0 da bunu tetikler! # ✅ Doğru: None'ı spesifik kontrol et if value is None: return "Eksik veri" if value == 0: return "Sıfır değer" if not value: # boş list/string vs return "Boş" return f"Değer: {value}" # Test print(process(None)) # 'Eksik veri' print(process(0)) # 'Sıfır değer' print(process("")) # 'Boş' print(process([])) # 'Boş' print(process(42)) # 'Değer: 42'
Pratik kural: Sayısal kontekstlerde (0 anlamlı bir değer olabilir) explicit veya kontrol yap. Container'larda (list/dict/string) truthy-check kullan.
is None== 0if not items:and ve or — short-circuit evaluation#
andorPython'da / C/Java'dakinden biraz farklı. Boolean değil, son değerlendirilen değeri dönüyor.
andor# and: ilk falsy değeri (veya son truthy değeri) döner print(5 and 10) # 10 (ikisi de truthy, son truthy) print(0 and 10) # 0 (ilk falsy — 10'a hiç bakmadı) print("" and "hello") # "" (boş string falsy) print([1] and [2]) # [2] # or: ilk truthy değeri (veya son falsy değeri) döner print(5 or 10) # 5 (ilk truthy) print(0 or 10) # 10 (0 falsy, 10'a baktı) print(None or "default") # "default" print("" or [] or "x") # "x"
Short-circuit avantajı#
# Default değer pattern display_name = user.nickname or user.username or "Misafir" # Sırayla: nickname truthy mi? Değilse username? Değilse "Misafir". # Lazy attribute access data = response and response.json() # response None ise, .json() çağırma; AttributeError'dan korur. # Conditional execution data and process(data) # data truthy ise process'i çağır
🚨 ile default tuzak: Eğer falsy ama anlamlı bir değer varsa (örn. 0):
or# Tuzak def get_count(items=None): count = items.count or 100 # items.count = 0 ise default 100 — istemediğin return count # Doğrusu def get_count(items=None): if items is None: count = 100 else: count = items.count return count # Veya ternary count = items.count if items is not None else 100
orif x is NoneorCustom class'larda truthiness — __bool__ ve __len__#
__bool____len__Kendi sınıfını da truthy/falsy yapabilirsin:
class ShoppingCart: def __init__(self): self.items = [] def add(self, item): self.items.append(item) def __bool__(self): """if cart: ... için.""" return bool(self.items) cart = ShoppingCart() print(bool(cart)) # False (boş items) if cart: print("Sepet dolu") else: print("Sepet boş") # bunu yazar cart.add("Elma") print(bool(cart)) # True
Eğer yoksa Python kullanır:
__bool____len__class Container: def __init__(self, items): self.items = items def __len__(self): return len(self.items) c1 = Container([]) c2 = Container([1, 2, 3]) print(bool(c1)) # False (len 0) print(bool(c2)) # True (len > 0)
Hiçbir method tanımlanmamışsa: nesne her zaman truthy (None hariç).
class Empty: pass print(bool(Empty())) # True (default) print(bool(None)) # False (özel)
Bu pattern Pythonic kod yazımının ana yollarından biri — veya gibi doğal okuyan koşullar.
if cart:if user:None — Python'un null'u#
None>>> type(None) <class 'NoneType'> # None her zaman aynı nesne (singleton) >>> a = None >>> b = None >>> a is b True # Hiç değiştirilemez (immutable) >>> None.x = 5 AttributeError: 'NoneType' object has no attribute 'x' # Aritmetik yok >>> None + 1 TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Ne için kullanılıyor?#
- Fonksiyon return değeri olmazsa default:
def greet(name): print(f"Merhaba {name}") # return yok! result = greet("Ali") print(result) # None (otomatik)
- Default argüman sentinel:
def search(query, limit=None): if limit is None: limit = 100 # ...
- Optional değer (var ya da yok):
def find_user(user_id): if user_id in database: return database[user_id] return None # Yok
- Mutable default tuzağına çözüm (Modül 2/Ders 1 hatırla):
def collect(items=None): if items is None: items = [] # ...
- Sentinel değer:
DELETED = None # işaretlemek için records = {1: "Ali", 2: DELETED, 3: "Ayşe"}
is None vs == None — kritik fark#
is None== NoneBu, Python'un en sık karıştırılan kurallarından biri. Cevap: her zaman .
is None# 🚫 if x == None: ... # ✅ if x is None: ...
Neden?
- Tutarlılık: tek bir nesne (singleton). Identity check (
None) bu nesneye bağlı; equality (is) custom class tarafından override edilebilir.==
class Weird: def __eq__(self, other): return True # her şeyle eşit gibi davranıyor! w = Weird() print(w == None) # True (yanıltıcı!) print(w is None) # False (gerçek)
-
Performans:daha hızlı. id karşılaştırması, method çağrısı yok.
is -
PEP 8 önerisi: Resmi.
-
Linter zorlar: Ruff, flake8, pylint hepsi'a uyarı atıyor.
== None
# Linter çıktısı if x == None: # E711 comparison to None should be 'if cond is None:'
Aynı kural: True ve False için de mı?#
PEP 8'e göre: hayır. ve için veya ikisi de OK ama explicit karşılaştırma çoğu zaman gereksiz.
TrueFalse== Trueis True# 🚫 Gereksiz if is_active == True: ... # ✅ Direkt if is_active: ... # 🚫 if condition is True: ... # ✅ if condition: ...
Bool için truthiness kullan, == ile karşılaştırma sürpriz davranışlar üretebilir (örneğin True döner ama False).
1 == True1 is TrueType hint: Optional ve X | None#
OptionalX | NonePython type hints'te "değer veya None olabilir" demek için Optional kullan:
from typing import Optional def find_user(user_id: int) -> Optional[str]: """Kullanıcı bulunursa adı, yoksa None döner.""" if user_id in database: return database[user_id] return None
Optional[X]Union[X, None]X | NoneModern Python (3.10+) için pipe syntax tercih ediliyor:
# Eski (3.9-) def find_user(user_id: int) -> Optional[str]: ... # Modern (3.10+) def find_user(user_id: int) -> str | None: ...
İkisi aynı şey. PEP 604.
Optional argüman da olabilir#
Optionaldef search(query: str, limit: int | None = None) -> list[str]: if limit is None: limit = 100 # ...
mypy/pyright bu signature'ı görünce, fonksiyon kullanan kodda None handling kontrolü yapıyor.
result = find_user(1) print(result.upper()) # mypy uyarır: result might be None! # Doğrusu — None check result = find_user(1) if result is not None: print(result.upper())
Type system seni güvenli kod yazmaya yönlendiriyor.
Sentinel pattern — None'ın "anlamlı yokluk"u#
Bazen "anlamlı bir değer olabilir; eksik mi yoksa explicit None mu?" karışıklığı yaratır:
Nonedef fetch(default=None): """default belirtilmemişse 100, None gelirse None bırak.""" if default is None: return 100 # ama belki kullanıcı bilerek None demek istedi! return default
Çözüm: özel sentinel kullan.
# Pattern 1: object() ile unique sentinel _MISSING = object() def fetch(default=_MISSING): if default is _MISSING: return 100 # parametre verilmedi return default # default = None bile olsa kullan # Test fetch() # 100 (verilmedi) fetch(None) # None (explicit None istendi) fetch(50) # 50 # Pattern 2: enum sentinel (Python 3.10+'ta typing.NoReturn benzeri) import enum class _Sentinel(enum.Enum): MISSING = "MISSING" MISSING = _Sentinel.MISSING def fetch(default=MISSING): if default is MISSING: return 100 return default
object()Bu pattern stdlib'de de kullanılıyor:
# inspect.Parameter.empty bir sentinel import inspect sig = inspect.signature(lambda x: x) param = list(sig.parameters.values())[0] print(param.default is inspect.Parameter.empty) # True
Kütüphane geliştirirken bu pattern hayat kurtarıyor — 'ın iki anlamı (parametre yok vs explicit None) ayrılıyor.
NonePratik patterns — gerçek kodda#
Pattern 1: Late default initialization#
def add_log(message, timestamp=None): if timestamp is None: timestamp = datetime.now() log.append((timestamp, message))
Default olamaz — fonksiyon tanımlandığı an bir kez evaluate olur, her çağrıda aynı zaman!
datetime.now()Pattern 2: Lazy property#
class User: def __init__(self, user_id): self.user_id = user_id self._profile = None # cache @property def profile(self): if self._profile is None: self._profile = fetch_profile(self.user_id) # pahalı return self._profile
NonePattern 3: Optional zinciri (chaining)#
# Java'da: user?.profile?.address?.city # Python equivalent: user = get_user(1) city = user.profile.address.city if (user and user.profile and user.profile.address) else None # Daha temiz pattern (3.8+ walrus + or): city = (user and user.profile and user.profile.address and user.profile.address.city) or "Unknown" # Veya try-except: try: city = user.profile.address.city except AttributeError: city = None # Veya getattr ile (en temiz): def safe_get(obj, *attrs): for attr in attrs: if obj is None: return None obj = getattr(obj, attr, None) return obj city = safe_get(user, 'profile', 'address', 'city')
Pattern 4: None veya raise — hangi ne zaman?#
Noneraise# Hata durumu için: # Yaklaşım 1: None dön (Pythonic, çağıran kontrol etsin) def find_user(user_id): return database.get(user_id) # None if not found user = find_user(123) if user is None: print("Bulunamadı") # Yaklaşım 2: Exception fırlat (Pythonic when 'eksik' anormal) def get_user(user_id): if user_id not in database: raise KeyError(f"User {user_id} not found") return database[user_id] try: user = get_user(123) except KeyError: print("Bulunamadı") # Yaklaşım 3: Default dön def get_user_or_default(user_id, default=None): return database.get(user_id, default)
Karar:
- "Eksik" beklenebilir → dön (
Nonegibi)dict.get() - "Eksik" hata durumu → Exception fırlat (gibi)
dict[key] - Çağıran her durumda devam edecek → default ile dön
Modern type-safe yaklaşım: veya (Rust tarzı).
Optional[User]Result[User, NotFound]Yaygın bool/None tuzakları#
1. if x: ile sayısal veri#
if x:def process(count): if count: # 🚫 do_work(count) # count=0 truthy değil! Bu fonksiyon 0 ile çağrıldığında do_work atlanır. # ✅ def process(count): if count > 0: do_work(count) # Veya: def process(count): if count is not None and count > 0: do_work(count)
2. return unutma#
returndef find(name, items): for item in items: if item.name == name: return item # return None EKSIK ama Python otomatik None dönüyor # Tip belli olsun diye explicit: def find(name, items): for item in items: if item.name == name: return item return None # explicit
Linter kuralı bunu uyarır. Modern stil: explicit .
PLR1711return None3. None karşılaştırması#
None# 🚫 if x == None: ... # ✅ if x is None: ...
4. Bool ile string formatla#
status = True print(f"Status: {status}") # "Status: True" print(f"Status: {int(status)}") # "Status: 1" # JSON'da import json json.dumps({"active": True}) # '{"active": true}' (lowercase!)
JSON lowercase. Python capital. Encoder otomatik çeviriyor.
trueTrue5. Empty collection truthiness#
results = search(query) # 🚫 Belirsiz if results: process(results) # Anlam: results None değilse VE liste boş değilse process et # Bu doğru mu? Bağlama bakıyorsun. Tehlikeli yer. # ✅ Açık if results is not None: if results: # boş değil process(results) else: print("Sonuç yok") # Veya: if results: process(results) elif results is None: print("Hata: arama yapılamadı") else: print("Sonuç bulunamadı")
6. Bool aritmetik istemeyen yerde#
# 🚫 Niyeti belli değil total = price + bonus * (rating > 4) # rating > 4 → True/False → 0/1 — çoğu okuyucu bilmiyor # ✅ bonus_amount = bonus if rating > 4 else 0 total = price + bonus_amount
Bu derste neler kazandın?#
✓ bool int'in alt sınıfı (True + 1 == 2!) — geriye uyumluluk hediyesi.
✓ Truthiness — her tip "doğru/yanlış" değerlendirilebilir.
✓ Falsy değerler tablosu: False, None, 0, 0.0, 0j, "", [], (), {}, set(), b"".
✓ Pythonic boş kontrolü.
if not items:✓ and/or short-circuit — boolean değil son değerlendirilen değer döner.
✓ ve ile custom truthiness.
__bool____len__✓ None — singleton, "değer yok" sentinel.
✓ vs — neden hep .
is None== Noneis✓ Optional type hint — ve modern .
Optional[X]X | None✓ Sentinel pattern — ile unique sentinel ile None'ın iki anlamı arasını ayırma.
object()✓ 5 pratik pattern: late default init, lazy property, Optional zinciri, None vs raise, default ile dön.
✓ 6 yaygın tuzak — sayısal truthiness, return unutma, == None, JSON casing, empty collection, bool aritmetik.
Sıradaki ders: Aritmetik operatörler. Görünüşte basit ama Python'da operator overloading var — nasıl çalışır? , , , magic methodları, Vector ve Money sınıflarıyla pratik örnekler.
+ - * /Vector(1,2) + Vector(3,4)__add____radd____iadd____neg__Sık Sorulan Sorular
Tamamen tasarım kararı. Guido van Rossum ABC dilinden ilham aldı (None ABC'den geliyor). 'null' diğer dillerde tip-belirsizlikten doğan kafa karışıklığı yaratıyor (Java'da NullPointerException, JS'de undefined vs null karmaşası). Python tek bir 'değer yok' sentinel'ı: None. Tek tip (NoneType), tek nesne (singleton), tutarlı davranış.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
İlgili İçerikler
Modül 1: Giriş ve Kurulum
Python Nedir, Neden Bu Kadar Popüler?
Öğrenmeye BaşlaModül 1: Giriş ve Kurulum
Python Sürümlerinin Tarihi: 2'den 3.14'e, AI Winter'lardan 'No-GIL' Devrimine
Öğrenmeye BaşlaModül 1: Giriş ve Kurulum