---
title: Koşullar
source: 'https://academia.sh/tr/kurslar/python-temelleri/kosullar'
course: 'Python Temelleri'
language: tr
updated: '2026-08-17T18:10:29+00:00'
license: 'CC BY-SA 4.0'
---

# Koşullar

Koşul bir mantıksal değer beklemez, nesneyi doğruluk kuralına sokar: on iki sınamada sekiz protokol çağrısı ölçülür, dördü hiçbir yöntem çağırmadan doğru döner ve karşılaştırma zinciri orta terimi bir kez üretir.

Önceki ders tip dönüşümünü ölçtü ve dönüşümün başarısız olduğu yerde bir **istisna**
doğduğunu gösterdi: nesne kendisinden istenen tipe karşılık veremediğinde soru yanıtsız
kalmaz, akış kesilir. Dönüşüm nesneye "sen bir tam sayı olarak neye karşılık geliyorsun?"
diye sorar ve bu sorunun yanıtsız kalma hakkı vardır.

Koşul ifadesi de nesneye bir soru sorar, ama başka bir soru: **"sen doğru mu
sayılıyorsun?"** Bu sorunun yanıtı, dönüşümdekinin tersine, neredeyse hiçbir zaman
istisna olmaz — nesne yanıtı kendisi vermezse dil onun yerine bir yanıt üretir. Peki o
yanıtı kim veriyor? `if` deyimi nesnenin içine bakıp öğe mi sayıyor, tipine mi bakıyor,
yoksa nesneye mi soruyor? Bu dersin ölçtüğü şey budur.

## Koşul Bir Mantıksal Değer Beklemez

Programlama Temelleri kursunun koşullu dallanma dersi koşulu **mantıksal değer üreten bir
ifade** olarak tanımlamıştı; o tanım dilden bağımsızdı ve dallanmayı bir **denetim yapısı**
olarak kurdu. Python'da tanım daha geniştir: `if` anahtar sözcüğünün arkasına **herhangi
bir nesne** yazılabilir ve dil onu bir doğruluk değerine kendisi indirger. Burada ölçülen
şey dallanmanın kendisi değil, o indirgemenin **hangi özel yöntemi çağırdığıdır**.

İndirgeme kuralına **doğruluk kuralı (truthiness)** denir ve üç basamaklıdır:

1. Nesnede `__bool__` tanımlıysa **o çağrılır**; döndürdüğü değer sonucun kendisidir.
2. Tanımlı değilse `__len__` **çağrılır**; sonuç sıfırdan büyükse nesne doğru sayılır.
3. İkisi de tanımlı değilse hiçbir yöntem çağrılmaz ve nesne **her zaman doğrudur**.

Üçüncü basamak kuralın en çok gözden kaçan yeridir. Boş bir nesnenin yanlış sayılması bir
dil kuralı değil, **nesnenin kendi bildirimidir**: bunu bildiren bir yöntem yoksa boşluk
diye bir kavram da yoktur. Sıradan bir nesne, içi ne olursa olsun, doğrudur.

## Zincir Bir Kısaltmadır

Karşılaştırma işleçleri Python'da zincirlenebilir: `a < b < c` geçerli bir ifadedir. Bu
yazımın anlamı soldan sağa ikili karşılaştırma **değildir** — öyle olsaydı `a < b` bir
doğruluk değeri üretir, o değer `c` ile karşılaştırılırdı ve sonuç anlamsız çıkardı.

Zincirin anlamı `a < b and b < c` ifadesidir; iki farkla. Birincisi, orta terim `b`
**bir kez** değerlendirilir. Açık yazımda `b` iki kez yazılır ve bir işlev çağrısıysa iki
kez çalışır. İkincisi, `and` gibi zincir de **kısa devre** yapar: ilk karşılaştırma yanlış
çıkarsa ikincisi hiç kurulmaz, sağdaki terim üretilmez bile.

Zincirleme kuralı yalnız `<` ve `>` için değil, **bütün karşılaştırma işleçleri** için
geçerlidir; üyelik ve kimlik işleçleri de aynı sınıftadır. Bu yüzden `a < b <= c` kadar
`a is b is c` de geçerli bir zincirdir ve aynı iki güvenceyi taşır. Zincirin uzunluğunda
bir sınır yoktur: her ek terim, bir öncekiyle kendi karşılaştırmasını kurar ve
soldakilerin hepsi doğru çıkmadıkça sıraya hiç gelmez.

İkisi de gözle görülmez. Terimlerin kaç kez üretildiğini anlamanın tek yolu, üretimi
sayan bir kurgu kurmaktır.

## Kısa Devrenin Döndürdüğü

`and` ve `or` işleçleri bir mantıksal değer döndürmez; **işlenenlerden birini** döndürür.
`x or y` ifadesi `x` doğruysa `x`'i, değilse `y`'yi verir. Döndürülen şey nesnenin
kendisidir, onun doğruluk değeri değil.

Bu ikisinin çağırdığı protokol de ayrıdır: `and` ve `or`, işlenenler üzerinde bir aritmetik
işleç gibi kendi özel yöntemini çağırmaz. Yaptıkları tek şey **sol işleneni doğruluk
kuralına sokmak** ve sonuca göre hangi işleneni döndüreceğine karar vermektir. Sağ işlenen,
gerekiyorsa döndürülür — sınanmaz.

Ölçümün varsayımları:

- **PA1** — Kâhin kurgunun kendisidir: hangi özel yöntemin çağrıldığını nesne kendi
  kaydettiği için bilinir; ölçüm dışarıdan bir gözlem değil, nesnenin kendi bildirimidir.
- **PA2** — Üç sınıf kullanılır. `Izci` yalnız `__len__` tanımlar, `Bosluksuz` ona
  `__bool__` ekler, `Sessiz` ikisini de tanımlamaz. Üç sınıf doğruluk kuralının üç
  basamağına birebir karşılık gelir.
- **PA3** — Her sınıf boş ve üç öğeli iki durumda sınanır; öğe sayısı sonucu değil,
  **sonucu kimin belirlediğini** ayırmak için değişir.
- **PA4** — Zincirin orta terimi bir işlev çağrısıyla üretilir ve her üretim kaydedilir;
  "kaç kez değerlendirildi" sorusunun ölçüsü bu kayıttır.
- **PA5** — `__lt__` uzunluğa göre karşılaştırır. Karşılaştırmanın **neye göre** yapıldığı
  ölçüme girmez; ölçülen şey **kaç kez** çağrıldığıdır.
- **PA6** — `Izci` yalnız `__lt__` tanımlar, karşıtı `__gt__` tanımsız bırakılır;
  yansımanın ölçülebilmesi için tanımsızlık kasıtlıdır.
- **PA7** — Sayılan çağrılar yalnız bu dersin kurduğu biçimlerden gelir; ortak tanımın
  diğer biçimleri bu ölçüme dahil değildir.

## Ölçüm

```python
"""Dogruluk kurali: if n hangi ozel yontemi cagirir, hangi sirayla."""

KAYIT = []


def kaydet(ad):
    KAYIT.append(ad)


class Izci:
    """__len__ tanimli, __bool__ tanimsiz."""

    def __init__(self, ogeler=(1, 2, 3)):
        self.ogeler = list(ogeler)

    def __len__(self):
        kaydet("__len__")
        return len(self.ogeler)

    def __lt__(self, o):
        kaydet("__lt__")
        return len(self.ogeler) < len(o.ogeler)


class Bosluksuz(Izci):
    """__bool__ tanimli: dogruluk sinamasi __len__'e dusmez."""

    def __bool__(self):
        kaydet("__bool__")
        return len(self.ogeler) > 0


class Sessiz:
    """Ne __bool__ ne __len__ tanimli."""

    def __init__(self, ogeler=()):
        self.ogeler = list(ogeler)


def olc(islev):
    KAYIT.clear()
    try:
        deger = islev()
    except Exception as e:
        KAYIT.append(f"!{type(e).__name__}")
        deger = None
    return list(KAYIT), deger


NESNELER = (
    ("Izci(3 oge)", lambda: Izci((1, 2, 3))),
    ("Izci(0 oge)", lambda: Izci(())),
    ("Bosluksuz(3 oge)", lambda: Bosluksuz((1, 2, 3))),
    ("Bosluksuz(0 oge)", lambda: Bosluksuz(())),
    ("Sessiz(3 oge)", lambda: Sessiz((1, 2, 3))),
    ("Sessiz(0 oge)", lambda: Sessiz(())),
)

print(f"{'nesne':<18s} {'if n':>6s} {'not n':>6s}  çağrılan protokol")
toplam = sinama = sessiz = 0
for ad, kur in NESNELER:
    n = kur()
    c1, d1 = olc(lambda: bool(n))
    c2, d2 = olc(lambda: not n)
    toplam += len(c1) + len(c2)
    sinama += 2
    sessiz += (len(c1) == 0) + (len(c2) == 0)
    print(f"  {ad:<16s} {str(d1):>6s} {str(d2):>6s}  {' '.join(c1) or '(yöntem yok)'}")
print(f"\nsınama {sinama}, çağrı {toplam}, hiçbir yöntemi çağırmayan {sessiz}")

URETIM = []


def uret(ad, n):
    URETIM.append(ad)
    return Izci(range(n))


def zincir():
    return uret("a", 1) < uret("b", 2) < uret("c", 3)


def acilim():
    return (uret("a", 1) < uret("b", 2)) and (uret("b", 2) < uret("c", 3))


def kisa_devre():
    return uret("a", 3) < uret("b", 2) < uret("c", 9)


print()
print(f"{'biçim':<16s} {'sonuç':>6s} {'__lt__':>7s} {'üretim':>7s}  sıra")
for ad, f in (("a<b<c", zincir), ("a<b and b<c", acilim),
              ("a<b<c  (yanlış)", kisa_devre)):
    URETIM.clear()
    c, d = olc(f)
    print(f"  {ad:<14s} {str(d):>6s} {c.count('__lt__'):7d}"
          f" {len(URETIM):7d}  {' '.join(URETIM)}")

print()
print(f"{'karşılaştırma':<24s} {'sonuç':>6s}  çağrılan protokol")
for ad, f in (("Izci(1) < Izci(2)", lambda: Izci((1,)) < Izci((1, 2))),
              ("Izci(2) > Izci(1)", lambda: Izci((1, 2)) > Izci((1,))),
              ("Sessiz(1) < Sessiz(2)", lambda: Sessiz((1,)) < Sessiz((1, 2)))):
    c, d = olc(f)
    print(f"  {ad:<22s} {str(d):>6s}  {' '.join(c)}")

print()
print(f"{'ifade':<26s} {'çağrı':>6s}  {'döndürülen tip':<16s} protokol")
BOS, DOLU = Izci(()), Bosluksuz((1, 2))
for ad, f in (("Izci(0) or Bosluksuz(2)", lambda: BOS or DOLU),
              ("Bosluksuz(2) or Izci(0)", lambda: DOLU or BOS),
              ("Izci(0) and Bosluksuz(2)", lambda: BOS and DOLU),
              ("bool(Izci(0) or Izci(0))", lambda: bool(Izci(()) or Izci(())))):
    c, d = olc(f)
    print(f"  {ad:<24s} {len(c):6d}  {type(d).__name__:<16s} {' '.join(c)}")
```

```
nesne                if n  not n  çağrılan protokol
  Izci(3 oge)        True  False  __len__
  Izci(0 oge)       False   True  __len__
  Bosluksuz(3 oge)   True  False  __bool__
  Bosluksuz(0 oge)  False   True  __bool__
  Sessiz(3 oge)      True  False  (yöntem yok)
  Sessiz(0 oge)      True  False  (yöntem yok)

sınama 12, çağrı 8, hiçbir yöntemi çağırmayan 4

biçim             sonuç  __lt__  üretim  sıra
  a<b<c            True       2       3  a b c
  a<b and b<c      True       2       4  a b b c
  a<b<c  (yanlış)  False       1       2  a b

karşılaştırma             sonuç  çağrılan protokol
  Izci(1) < Izci(2)        True  __lt__
  Izci(2) > Izci(1)        True  __lt__
  Sessiz(1) < Sessiz(2)    None  !TypeError

ifade                       çağrı  döndürülen tip   protokol
  Izci(0) or Bosluksuz(2)       1  Bosluksuz        __len__
  Bosluksuz(2) or Izci(0)       1  Bosluksuz        __bool__
  Izci(0) and Bosluksuz(2)      1  Izci             __len__
  bool(Izci(0) or Izci(0))      2  bool             __len__ __len__
```

## Üç Basamağın Bedeli

Üst tablo doğruluk kuralının üç basamağını yan yana koyuyor. **On iki sınamada sekiz
çağrı** var; aradaki dört sınama **hiçbir yöntemi çağırmadan** sonuç üretiyor.

İlk iki satır ikinci basamak: `Izci` `__bool__` tanımlamadığı için sınama `__len__`'e
düşüyor ve sonucu öğe sayısı belirliyor. Üçüncü ve dördüncü satır birinci basamak: aynı
sınıfa `__bool__` eklendiği anda `__len__` **hiç çağrılmıyor**. İkisi de tanımlıyken hangi
yöntemin çağrılacağı sorusu yok — `__bool__` varsa `__len__` sınamaya katılmaz.

Son iki satır üçüncü basamak ve tablonun asıl sonucu burada. `Sessiz(0 oge)` **boş**, ama
sınama **doğru** veriyor. Üstelik bunu bir yöntem çağırarak değil, **hiç çağırmayarak**
yapıyor. Nesnenin üç öğesi mi var, sıfır mı — sonucu değiştirmiyor, çünkü sonucu üretecek
bir yöntem yok. Bu satırın pratik karşılığı şudur: kendi yazdığı bir sınıfın boş örneğini
`if` ile sınayan bir program, `__len__` ya da `__bool__` yazmayı unutmuşsa **her zaman
doğru** dalını alır ve bunu bildiren hiçbir belirti çıkmaz.

`not n` sütunu aynı zincirin bir kez daha yürüdüğünü gösteriyor: olumsuzlama ayrı bir
protokol değil, aynı sınamanın sonucunun tersidir. Sütunlardaki tek fark `Sessiz`
satırlarında görülüyor — `not` bir nesne değil, gerçek bir mantıksal değer döndürüyor.

## Zincir Kaç Terim Üretiyor

Orta tablo zincirin kısaltma olduğunu sayıyla gösteriyor. `a<b<c` ile açık yazımın
`__lt__` sayısı aynı: **ikisi de 2**. Karşılaştırma sayısında bir kazanç yok.

Fark üretim sütununda. Zincir üç terim üretiyor, açık yazım **dört**: `b` iki kez
üretiliyor. Bu, okunabilirlik değil **anlam** farkıdır. Orta terim bir işlev çağrısıysa
o işlev iki kez çalışır; yan etkisi varsa yan etki iki kez oluşur; her çağrıda başka bir
değer döndürüyorsa iki karşılaştırma **birbirinden habersiz iki ayrı değeri** sınar. Açık
yazım, zincirin verdiği güvenceyi vermez.

Üçüncü satır kısa devreyi ölçüyor. İlk karşılaştırma yanlış çıktığı için `__lt__`
**1** kez çağrılıyor ve üretim **2**'de duruyor: `c` hiç kurulmuyor. Zincirin sağ ucundaki
terim, sola bakılmadan üretilmeyecek bir şeydir.

## Ters Yönde Bulunan Protokol

Üçüncü tablo karşılaştırmanın kendi düşme kuralını gösteriyor ve ortadaki satır dersin en
sert sonucudur. `Izci` sınıfı `__lt__` tanımlar, `__gt__` tanımlamaz. Buna rağmen
`Izci(2) > Izci(1)` çalışıyor — ve çağrılan yöntem **`__lt__`**.

Kural şudur: bir karşılaştırmada sol işlenenin yöntemi bulunamazsa dil **sağ işlenenin
karşıt yöntemini** dener. `a > b` için önce `a` üzerinde `__gt__` aranır; yoksa `b`
üzerinde `__lt__` çağrılır ve işlenenler yer değiştirir. Sonuç doğru çıkar, çünkü
"`b`, `a`'dan küçüktür" ile "`a`, `b`'den büyüktür" aynı iddiadır.

Bunun sonucu doğrudan ikinci iddiadır: **yazılan işleç, çağrılan yöntemin adını
söylemez.** İki satır sonucu `True` veriyor, ikisi de aynı yöntemi çağırıyor, ama biri
`<` biri `>` yazıyor. Sözdizime bakarak hangi yöntemin çalıştığını kestirmek olanaksızdır;
bunu yalnız ölçüm söyler.

Üçüncü satır kuralın sonunu gösteriyor. `Sessiz` ne `__lt__` ne `__gt__` tanımlar; ne sol
işlenende ne sağ işlenende bir yöntem bulunuyor ve karşılaştırma bir sonuç değil,
`TypeError` üretiyor. Doğruluk sınamasının üçüncü basamağı sessizce doğru dönerken,
karşılaştırmanın son basamağı **istisnayla** biter: bir sözdizim için varsayılan davranış
var, öbürü için yok. Protokolü olmayan nesne, o sözdizimi hiç taşımaz.

## Koşul Deyimi ile Koşul İfadesi

Doğruluk kuralı yalnız `if` deyiminde çalışmaz. Aynı indirgeme `while` koşulunda, `and` ve
`or` işleçlerinde, `not` işlecinde ve **koşul ifadesinde** de yürür.

Koşul ifadesi, önceki konunun deyim ile ifade ayrımını kullanır: `if` bir **deyimdir**,
değer üretmez ve bir atamanın sağına yazılamaz. Bunun ifade karşılığı `a if k else b`
yazımıdır ve bir **değer üretir** — dolayısıyla bir atamanın sağına, bir argümanın yerine
ya da bir listenin içine konabilir.

İkisi arasındaki fark yalnız yazımdadır; doğruluk kuralı ikisinde de aynı üç basamağı
yürütür ve `k` yerine yazılan nesne aynı ölçümden geçer. Kısa devre de korunur: koşul
ifadesinde `a` ile `b` dallarından **yalnız biri** değerlendirilir. Bu, koşul ifadesini
`and` ve `or` zincirlerinden ayıran şeydir — orada döndürülen değer işlenenlerden biriydi,
burada seçilen dalın kendisidir ve seçilmeyen dal hiç kurulmaz.

## Döndürülen Nesnenin Tipi

Alt tablo `and` ile `or` işleçlerinin ne döndürdüğünü gösteriyor ve üç satırının üçünde de
dönen şey **bir mantıksal değer değil**.

İlk satır: sol işlenen `Izci(0)` boş, sınama `__len__` ile yanlış çıkıyor, `or` sağ
işleneni döndürüyor — dönen tip `Bosluksuz`. İkinci satır: sol işlenen bu kez doğru,
`__bool__` ile sınanıyor ve `or` **sol işleneni** döndürüyor. Üçüncü satırda `and` tersini
yapıyor: sol işlenen yanlış olduğu için sonuç doğrudan **o** oluyor, tip `Izci`.

Üç satırın da çağrı sayısı **1**. Sağ işlenen hiçbir zaman sınanmıyor; yalnız döndürülüyor.
Bunun sonucu, `or` ile yazılan varsayılan değer kalıbının Python'da tam olarak ne yaptığıdır:
sol işlenen doğruluk kuralından yanlış çıkarsa sağdaki verilir — **boş** olduğu için değil,
**yanlış sayıldığı** için.

Son satır ikisini ayırıyor. `bool()` yerleşiği araya girdiğinde dönen tip gerçekten `bool`
oluyor ve çağrı sayısı **2**'ye çıkıyor: bir kez `or` sol işleneni sınıyor, bir kez de
`bool()` sonucu sınıyor. Aynı ifadeyi mantıksal değere çevirmenin bedeli fazladan bir
protokol çağrısıdır.

## Özet

- Python'da koşul mantıksal değer beklemez; `if` arkasındaki her nesne **doğruluk
  kuralından** geçirilir ve ölçülen şey bu indirgemenin çağırdığı özel yöntemdir.
- Kural üç basamaklıdır: `__bool__` varsa o çağrılır, yoksa `__len__`'e düşülür, o da
  yoksa **hiçbir yöntem çağrılmadan** nesne doğru sayılır — on iki sınamanın dördü bu
  basamakta ve boş nesne bile doğru döner.
- `__bool__` tanımlıyken `__len__` sınamaya hiç katılmaz; iki yöntem yarışmaz, ilki
  ikincisini devre dışı bırakır.
- Karşılaştırma zinciri `a<b<c` ile açık yazım aynı sayıda `__lt__` çağırır (**2**), ama
  zincir orta terimi **bir kez** üretir, açık yazım **iki kez**; zincir yanlış çıktığında
  sağ terim hiç üretilmez.
- Karşılaştırmanın kendi düşme kuralı vardır: sol işlenende yöntem yoksa sağ işlenenin
  karşıtı çağrılır — `>` yazılan bir ifade `__lt__` çalıştırır; ikisi de yoksa sonuç
  bir değer değil, `TypeError` olur.
- `and` ile `or` bir mantıksal değer değil, **işlenenlerden birini** döndürür; yalnız sol
  işleneni doğruluk kuralına sokarlar, sağ işleneni sınamazlar.

## Sonraki Adım

Doğruluk kuralı tek bir soruyu bir kez sorar ve yanıtı bir dalla biter. Döngü ise aynı
soruyu değil, **başka bir soruyu tekrar tekrar** sorar: sırada bir öğe var mı? Programlama
Temelleri kursunda döngü bir denetim yapısıydı; kaç tur döneceği koşula ya da koleksiyonun
uzunluğuna bağlıydı. Python'da döngü bir **protokoldür** ve turların bitmesine karar veren
şey bir koşul değildir. Sonraki ders üç öğelik bir nesnede döngünün kaç kez `__next__`
çağırdığını sayar — ve o sayının neden öğe sayısından bir fazla olduğunu.
