Python 3.10 ile gelen match deyimi, bir değeri sırayla yazılmış case desenleriyle karşılaştırır ve yalnızca ilk eşleşen bloğu çalıştırır. İlk bakışta C veya JavaScript'teki switch'e benzer, ama resmî Tutorial'ın ifadesiyle Rust veya Haskell'deki desen eşleştirmeye (pattern matching) daha yakındır: Desenler yalnızca sabit değerleri karşılaştırmaz, listelerin elemanlarını, sözlüklerin anahtarlarını ve nesnelerin özelliklerini değişkenlere ayırarak yakalayabilir. case _: her şeyle eşleşen joker (wildcard) desendir; hiçbir desen eşleşmezse hiçbir blok çalışmaz ve hata da oluşmaz.
Bu yazıda desen türlerini (literal, yakalama, dizi, sözlük, sınıf, OR ve AS desenleri), koruma koşullarını (guard) ve en sık yapılan hataları Language Reference'ın match bölümüne ve Tutorial'a dayanarak anlatıyoruz. Bütün örnekler Python 3.15.2 ile çalıştırıldı. Basit koşullar için if/elif/else yazısı daha uygun bir başlangıçtır.
En basit kullanım: literal desenler

En basit biçimde match'in yanındaki değer (konu, subject) her case'teki sabitle karşılaştırılır. | işaretiyle birden fazla sabiti tek desende birleştirebilirsiniz; buna OR deseni denir. case _: en sona konur ve geri kalan her durumu yakalar.
def http_durum(kod):
match kod:
case 200:
return 'Tamam'
case 400:
return 'Hatalı istek'
case 401 | 403:
return 'Yetki yok'
case 404:
return 'Bulunamadı'
case _:
return 'Bilinmeyen durum'
for k in (200, 403, 404, 500):
print(k, http_durum(k))
# çıktı: 200 Tamam
# çıktı: 403 Yetki yok
# çıktı: 404 Bulunamadı
# çıktı: 500 Bilinmeyen durumC'deki switch'ten farklı olarak break yazmanız gerekmez ve bir bloktan diğerine düşme (fall-through) olmaz: İlk eşleşen blok çalışır, gerisi denenmez. Hiçbir desen eşleşmezse match sessizce biter:
def kontrol(x):
match x:
case 1:
print('bir')
print('match bitti')
kontrol(5) # çıktı: match bittimatch ve case yumuşak anahtar kelimedir
Language Reference'a göre match, case ve _ yumuşak anahtar kelimelerdir (soft keyword): Yalnızca bu deyimin içinde özel anlam taşırlar. Bu sayede 3.10'dan önce yazılmış ve match adında değişken veya fonksiyon kullanan kodlar bozulmadı. Örneğin re modülündeki re.match() fonksiyonu hâlâ bu adı taşır (Python 3.15 yeni kod için re.prefixmatch() adını öneriyor, ama belgelere göre eski ad kaldırılmayacak).
match = 'değişken adı olarak da kullanılabilir'
print(match) # çıktı: değişken adı olarak da kullanılabilirLiteral desenler == ile, None/True/False is ile karşılaştırılır
Belgelere göre literal desenlerin çoğu eşitlikle (==) karşılaştırılır; None, True ve False tekil nesneleri ise kimlikle (is). Bunun az bilinen bir sonucu vardır: Python'da True == 1 doğru olduğu için case 1: deseni True değeriyle de eşleşir, ama case True: deseni 1 ile eşleşmez. Desenlerde metin (normal, ham ve üç tırnaklı) ve bayt literalleri kullanılabilir, f-string ve t-string kullanılamaz. Python 3.15 ile literal desenlerde, zaten desteklenen eksi işaretine ek olarak tekli artı işareti de (case +1:) kabul edilmeye başladı.
match True:
case 1:
print('case 1, True ile eşleşti')
match 1:
case True:
print('eşleşti')
case _:
print('case True, 1 ile eşleşmedi')
match 1:
case +1: # Python 3.15 ve sonrası
print('artı işaretli literal')
# çıktı: case 1, True ile eşleşti
# çıktı: case True, 1 ile eşleşmedi
# çıktı: artı işaretli literalYakalama desenleri ve dizi desenleri
Desende tek başına yazılan bir ad (örneğin y) bir yakalama desenidir (capture pattern): Her zaman eşleşir ve karşılık gelen değeri o ada atar. Tutorial, desenleri bir atamanın sol tarafının genişletilmiş hâli gibi okumayı önerir: case (x, y): deseni, (x, y) = nokta açma atamasına kavramsal olarak benzer. Literal ve yakalama desenleri bir arada kullanılabilir:
def nokta(p):
match p:
case (0, 0):
return 'Başlangıç noktası'
case (0, y):
return f'Y ekseni üzerinde, y={y}'
case (x, 0):
return f'X ekseni üzerinde, x={x}'
case (x, y):
return f'x={x}, y={y}'
case _:
return 'Nokta değil'
for p in [(0, 0), (0, 5), (3, 0), [2, 7], (1, 2, 3), 'ab']:
print(nokta(p))
# çıktı: Başlangıç noktası
# çıktı: Y ekseni üzerinde, y=5
# çıktı: X ekseni üzerinde, x=3
# çıktı: x=2, y=7
# çıktı: Nokta değil
# çıktı: Nokta değilÇıktıdaki üç ayrıntı belgelerdeki kuralları gösterir. Birincisi, demet ve liste desenleri aynı anlama gelir ve herhangi bir diziyle eşleşir; bu yüzden [2, 7] listesi (x, y) deseniyle eşleşti. İkincisi, yıldızsız bir dizi deseni sabit uzunlukludur; üç elemanlı demet iki elemanlı desene uymadı. Üçüncüsü, dizi desenleri str, bytes ve bytearray ile hiç eşleşmez; 'ab' iki karakterli olsa da (x, y) desenine girmedi. Yineleyiciler de dizi sayılmaz.
Yakalanan adlar nereye atanır? Language Reference'a göre yakalama desenleri, atama ifadesi (:=) ile aynı kapsam kurallarını izler: Ad, en yakın fonksiyon kapsamında yerel değişken olur; o fonksiyonda global veya nonlocal bildirimi varsa ona uyulur. Yani case bloğu ayrı bir kapsam oluşturmaz; kapsam kuralları kapsam yazısında anlatılıyor.
Yıldızlı desenler ve komut ayrıştırma
Dizi desenleri, açma atamalarındaki gibi yıldızlı bir alt desen alabilir: [ilk, *kalan] en az bir elemanlı her diziyle eşleşir ve kalan elemanları liste olarak yakalar. Belgelere göre bir dizi deseninde en fazla bir yıldızlı alt desen olabilir ve bu desen herhangi bir konumda durabilir. *_ kalan elemanları bağlamadan yok sayar. Bu özellik, kullanıcının yazdığı bir komutu kelimelerine ayırıp işlemek için çok uygundur:
def komut_isle(satir):
match satir.split():
case []:
return 'Boş komut'
case ['çık' | 'q']:
return 'Çıkılıyor'
case ['git', yon] if yon in ('kuzey', 'güney', 'doğu', 'batı'):
return f'{yon} yönüne gidiliyor'
case ['git', yon]:
return f'Bilinmeyen yön: {yon}'
case ['al', *esyalar] if esyalar:
return 'Alındı: ' + ', '.join(esyalar)
case ['al']:
return 'Ne alınacak?'
case [komut, *_]:
return f'Bilinmeyen komut: {komut}'
for s in ['', 'q', 'git kuzey', 'git yukarı', 'al anahtar fener', 'al', 'zıpla yüksek']:
print(komut_isle(s))
# çıktı: Boş komut
# çıktı: Çıkılıyor
# çıktı: kuzey yönüne gidiliyor
# çıktı: Bilinmeyen yön: yukarı
# çıktı: Alındı: anahtar, fener
# çıktı: Ne alınacak?
# çıktı: Bilinmeyen komut: zıpla['çık' | 'q'] deseni, tek elemanlı ve o elemanı 'çık' ya da 'q' olan listelerle eşleşir; OR deseni bir alt desen olarak iç içe kullanılabilir. Belgelerin bir notu: Köşeli parantez içindeki tek desen ([3 | 4]) hâlâ bir dizi desenidir, ama sondaki virgül olmadan normal parantez içindeki tek desen ((3 | 4)) yalnızca bir gruplama desenidir.
Koruma koşulu (guard)

Bir desenden sonra if koşul yazarak ek bir şart ekleyebilirsiniz; buna koruma koşulu (guard) denir. Language Reference akışı şöyle tanımlar: Önce desen denenir; desen başarısızsa koşul hiç değerlendirilmez. Desen başarılıysa koşul değerlendirilir; doğruysa blok seçilir, yanlışsa bir sonraki case denenir. Koşul değerlendirilirken desenin yaptığı bütün bağlamalar yapılmış olur, bu yüzden koşul yakalanan değişkenleri kullanabilir. Koşul bir istisna yükseltirse istisna dışarı çıkar. Yukarıdaki ['git', yon] if yon in (...) satırı tam olarak bunu yapıyor: Yön geçersizse koşul yanlış olur ve sıradaki ['git', yon] deseni devreye girer.
Konuyu demet olarak vermek
match'in yanındaki ifade virgül içeriyorsa Python normal kurallarla bir demet oluşturur. Bu, iki değeri birlikte değerlendirmek için kısa bir yoldur. Aşağıdaki FizzBuzz uyarlaması bölümden kalanları demet olarak eşleştirir:
def fizzbuzz(n):
match n % 3, n % 5:
case 0, 0:
return 'FizzBuzz'
case 0, _:
return 'Fizz'
case _, 0:
return 'Buzz'
case _:
return str(n)
print(' '.join(fizzbuzz(i) for i in range(1, 16)))
# çıktı: 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzzSözlük (mapping) desenleri
{'anahtar': desen} biçimindeki desenler sözlük gibi eşleme (mapping) nesneleriyle eşleşir. Dizi desenlerinden farklı olarak fazla anahtarlar yok sayılır: Desende geçen anahtarların sözlükte bulunması ve değerlerinin alt desenlere uyması yeterlidir. Kalan anahtarları toplamak için en sona **ad yazılabilir; **_ ise gereksiz olduğu için izin verilmez. Bu desenler JSON'dan gelen olay veya mesaj verilerini işlemek için çok kullanışlıdır:
def olay_isle(olay):
match olay:
case {'tur': 'giris', 'kullanici': ad}:
return f'{ad} giriş yaptı'
case {'tur': 'satis', 'tutar': int(tutar) | float(tutar)} if tutar > 0:
return f'Satış: {tutar} TL'
case {'tur': 'hata', **ayrinti}:
return f'Hata ayrıntısı: {ayrinti}'
case {'tur': tur}:
return f'İşlenmeyen olay türü: {tur}'
case _:
return 'Geçersiz olay'
print(olay_isle({'tur': 'giris', 'kullanici': 'ece', 'zaman': '10:00'}))
print(olay_isle({'tur': 'satis', 'tutar': 250}))
print(olay_isle({'tur': 'satis', 'tutar': '250'}))
print(olay_isle({'tur': 'hata', 'kod': 500, 'mesaj': 'zaman aşımı'}))
print(olay_isle(['tur', 'giris']))
# çıktı: ece giriş yaptı
# çıktı: Satış: 250 TL
# çıktı: İşlenmeyen olay türü: satis
# çıktı: Hata ayrıntısı: {'kod': 500, 'mesaj': 'zaman aşımı'}
# çıktı: Geçersiz olayMetin olarak gelen '250' tutarı int(tutar) | float(tutar) alt desenine uymadığı için bir sonraki genel desene düştü; desenler böylece tip doğrulamasını da üstlenebilir. Belgelere göre eşleştirme, sözlüğün iki argümanlı get() metoduyla yapılır; yani anahtarın gerçekten sözlükte bulunması gerekir, defaultdict gibi yapılarda __missing__() ile anında oluşturulan değerler sayılmaz. Aynı sabit anahtarı bir desende iki kez yazmak SyntaxError verir. JSON verisini Python'a almak için json modülü yazısına bakın.
Sınıf desenleri
Verilerinizi sınıflarla tutuyorsanız, sınıf adından sonra kurucu çağrısına benzeyen bir argüman listesi yazarak hem tipi kontrol edebilir hem de özellikleri yakalayabilirsiniz. Language Reference'a göre Sinif(...) deseni önce isinstance() testi yapar, sonra ad=desen biçimindeki her anahtar kelimeyi nesnenin özelliği olarak arar. Konumsal alt desenler ise sınıfın __match_args__ özelliğindeki sıraya göre özellik adlarına çevrilir. Sinif() gibi argümansız bir desen yalnızca tipi kontrol eder.
class Nokta:
__match_args__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
def nerede(n):
match n:
case Nokta(x=0, y=0):
return 'Orijin'
case Nokta(0, y):
return f'Y ekseni, y={y}'
case Nokta(x, y) if x == y:
return f'Köşegen üzerinde, {x}'
case Nokta():
return 'Başka bir yerde'
case _:
return 'Nokta değil'
for n in (Nokta(0, 0), Nokta(0, 4), Nokta(2, 2), Nokta(1, 5), (1, 5)):
print(nerede(n))
# çıktı: Orijin
# çıktı: Y ekseni, y=4
# çıktı: Köşegen üzerinde, 2
# çıktı: Başka bir yerde
# çıktı: Nokta değilTutorial'ın önemli bir uyarısı: Desende yalnızca tek başına duran adlar (yukarıdaki y, x) atanır. Noktalı adlar (Renk.KIRMIZI), özellik adları (x= kısmı) ve sınıf adları (Nokta) asla atanmaz. dataclass ile oluşturulan sınıflar __match_args__'ı otomatik tanımlar, bu yüzden konumsal desenleri ek bir ayar yapmadan kullanabilirsiniz:
from dataclasses import dataclass
@dataclass
class Daire:
yaricap: float
@dataclass
class Dikdortgen:
en: float
boy: float
def tarif(sekil):
match sekil:
case Daire(r):
return f'Daire, yarıçap {r}'
case Dikdortgen(en, boy) if en == boy:
return f'Kare, kenar {en}'
case Dikdortgen(en, boy):
return f'Dikdörtgen, {en} x {boy}'
print(Dikdortgen.__match_args__) # çıktı: ('en', 'boy')
print(tarif(Daire(3))) # çıktı: Daire, yarıçap 3
print(tarif(Dikdortgen(4, 4))) # çıktı: Kare, kenar 4
print(tarif(Dikdortgen(2, 5))) # çıktı: Dikdörtgen, 2 x 5Yerleşik tiplerle tip kontrolü
bool, int, float, str, bytes, bytearray, list, tuple, dict, set, frozenset ve Python 3.15'te eklenen frozendict için konumsal alt desen özel çalışır: Tek bir alt desen, özelliğe değil nesnenin tamamına uygulanır. Belgelerdeki örneğe göre int(0|1) deseni 0 değeriyle eşleşir ama 0.0 ile eşleşmez. Burada dikkat edilmesi gereken nokta bool'un int'in alt sınıfı olmasıdır: int() deseni True ile de eşleşir, bu yüzden bool() desenini önce yazın.
def tip_adi(deger):
match deger:
case bool():
return 'mantıksal'
case int() | float():
return 'sayı'
case str() as metin if not metin:
return 'boş metin'
case str():
return 'metin'
case [*_]:
return 'dizi'
case {}:
return 'eşleme'
case None:
return 'None'
case _:
return 'diğer'
for d in (True, 3, 2.5, '', 'abc', [1], (1, 2), {'a': 1}, None, {1, 2}):
print(repr(d), tip_adi(d))
# çıktı: True mantıksal
# çıktı: 3 sayı
# çıktı: 2.5 sayı
# çıktı: '' boş metin
# çıktı: 'abc' metin
# çıktı: [1] dizi
# çıktı: (1, 2) dizi
# çıktı: {'a': 1} eşleme
# çıktı: None None
# çıktı: {1, 2} diğercase {}: deseni boş sözlük demek değildir; fazla anahtarlar yok sayıldığı için her eşleme nesnesiyle eşleşir. Küme (set) ise ne dizi ne eşleme olduğu için joker desene düştü. str() as metin kısmı bir AS desenidir: Sol taraftaki desen eşleşirse konunun tamamı sağdaki ada atanır.
AS deseni iç içe yapılarda özellikle işe yarar: Bir alt yapıyı hem parçalarına ayırıp hem de bütün olarak saklamanızı sağlar. Belgelere göre as'in sağındaki ad _ olamaz.
match [3, (1, 2)]:
case [int() as adet, (x, y) as cift]:
print(adet, x, y, cift) # çıktı: 3 1 2 (1, 2)En sık hata: sabit sanılan yakalama deseni
case'te tek başına yazılan ad bir sabit değil, yakalama desenidir. Bir sabitle karşılaştırmak isteyip case KIRMIZI: yazarsanız bu desen her değerle eşleşir ve KIRMIZI değişkeninin üzerine yazar. Python bu hatanın bir kısmını derleme sırasında yakalar: Böyle bir desenin altına başka case yazarsanız SyntaxError: name capture 'KIRMIZI' makes remaining patterns unreachable alırsınız. Tek case varsa hata olmaz, ama sonuç yanlıştır:
KIRMIZI = 'kırmızı'
renk = 'mavi'
match renk:
case KIRMIZI: # sabit değil, yakalama deseni!
print('Eşleşti:', KIRMIZI)
print(KIRMIZI)
# çıktı: Eşleşti: mavi
# çıktı: maviTutorial'ın çözümü, sabitleri noktalı adlarla kullanmaktır; noktalı adlar yakalama değil değer deseni sayılır ve == ile karşılaştırılır. En temiz yol bir Enum tanımlamaktır:
from enum import Enum
class Renk(Enum):
KIRMIZI = 'kırmızı'
MAVI = 'mavi'
match Renk('mavi'):
case Renk.KIRMIZI:
print('Kırmızı seçildi')
case Renk.MAVI:
print('Mavi seçildi')
# çıktı: Mavi seçildiEnum kullanımının ayrıntıları enum yazısında anlatılıyor.
Diğer kurallar

- Her şeyi yakalayan blok en sonda olmalı: Belgelere göre bir
match'te koşulsuz ve her zaman eşleşen en fazla bir blok olabilir ve son sırada durmalıdır.case _:altına başka blok yazmakSyntaxError: wildcard makes remaining patterns unreachableverir. - Bağlamalar match'ten sonra da yaşar: Başarılı bir eşleşmede atanan adlar blok bittikten sonra da kullanılabilir. Başarısız denemelerde ise bazı alt desenler bağlama yapmış olabilir; belgeler bunlara güvenmemenizi açıkça söyler.
- OR desenindeki her seçenek aynı adları bağlamalı:
case (x, 0) | (0, x):geçerlidir; seçeneklerden biriybağlıyorsa diğeri de bağlamalıdır. - Bir desende aynı ad iki kez bağlanamaz:
case x, x:geçersizdir. - Desenler değerlendirilme sayısına güvenmeyin: Belgelere göre yorumlayıcı değerleri önbelleğe alabilir veya tekrarlanan değerlendirmeleri atlayabilir.
match mi, if/elif mi?
| Durum | Uygun yapı |
|---|---|
| Tek bir değeri birkaç sabitle karşılaştırmak | İkisi de olur; match daha düzenli görünür |
| Aralık kontrolü (x > 10 gibi) | if/elif (match içinde guard gerekir) |
| Listenin uzunluğuna ve elemanlarına göre dallanmak | match (dizi desenleri) |
| JSON benzeri sözlüklerin yapısına göre dallanmak | match (sözlük desenleri) |
| Nesnenin tipine ve özelliklerine göre dallanmak | match (sınıf desenleri) |
| Python 3.9 veya daha eski sürümü desteklemek | if/elif (match 3.10 ile geldi) |
Sık Sorulan Sorular
Python'da switch case var mı?
Ayrı bir switch deyimi yoktur. Python 3.10'dan itibaren match/case bu işi görür; daha eski sürümlerde ve basit durumlarda if/elif/else zinciri kullanılır.
case içinde break yazmam gerekir mi?
Hayır. Yalnızca ilk eşleşen blok çalışır ve sonraki bloklara geçiş olmaz.
Hiçbir case eşleşmezse ne olur?
Hiçbir blok çalışmaz ve program match'ten sonraki satırdan devam eder; hata oluşmaz. Varsayılan davranış için en sona case _: ekleyin.
Bir değişkenin değeriyle nasıl karşılaştırırım?
Çıplak ad yakalama deseni olduğu için ya noktalı bir ad kullanın (Renk.KIRMIZI, ayar.SINIR) ya da case x if x == hedef: gibi bir koruma koşulu yazın.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Python öğrenme rehberi · if/elif/else koşulları · Enum kullanımı · dataclasses · Tuple ve unpacking · Sözlük metotları · class ve nesne