Python'da enum modülü, sınırlı sayıda seçenekten birini alabilen değerler için adlandırılmış sabitler tanımlamanızı sağlar. class Durum(Enum): altına KARGODA = 3 gibi satırlar yazdığınızda her satır bir üye (member) olur; üyenin name ve value öznitelikleri vardır, Durum(3) ile değerden, Durum['KARGODA'] ile addan üyeye ulaşılır. Tam sayı gibi davranması gereken sabitler için IntEnum, metin gibi davrananlar için StrEnum, bit bayrakları için Flag ve IntFlag kullanılır; değerleri elle yazmak istemezseniz auto() devreye girer.
Bu yazıda Enum üyelerinin nasıl oluşturulup arandığını, takma adları (alias) ve @unique'i, karşılaştırma kurallarını, IntEnum ile StrEnum'un farkını, auto() değerlerini, Flag birleşimlerini, Enum'a metot ve öznitelik eklemeyi, _missing_ ile esnek aramayı ve fonksiyonel API'yi Python 3.15.2 ile çalıştırılmış örneklerle anlatıyoruz. Sınıf temelleri için class ve nesne yazısına, serinin tamamı için Python öğrenme rehberine göz atabilirsiniz.
Neden düz sabitler yerine Enum?

KARGODA = 3 gibi modül düzeyinde bir sabit de iş görür, ama hata ayıklarken ekranda yalnızca 3 görürsünüz ve o sayının hangi kümeye ait olduğu belli olmaz. Enum HOWTO belgesi Enum'ları global değişkenlere benzetir, ancak daha kullanışlı bir repr(), gruplama ve tip güvenliği sunduklarını vurgular. Bir sipariş durumu yanlışlıkla bir ödeme durumuyla karşılaştırılamaz, bir fonksiyon yalnızca Durum üyelerini kabul edecek şekilde denetlenebilir ve geçerli seçeneklerin tam listesi her zaman sınıfın üzerinden okunabilir.
Adlandırma için belgelerin güçlü önerisi üyeleri BÜYÜK_HARFLE yazmaktır: üyeler sabit oldukları için hem okunabilirlik artar hem de karışım (mixin) sınıflarının metot adlarıyla çakışma riski azalır. Bu yazıdaki örneklerde üye adlarını Türkçe ama ASCII harflerle (YUKSEK, GUNEY) yazdık.
Enum tanımlama, arama ve yineleme
from enum import Enum
class Durum(Enum):
BEKLIYOR = 1
HAZIRLANIYOR = 2
KARGODA = 3
TESLIM = 4
print(Durum.KARGODA)
print(repr(Durum.KARGODA))
print(Durum.KARGODA.name, Durum.KARGODA.value)
print(Durum(2), Durum['TESLIM'])
print(type(Durum.TESLIM), isinstance(Durum.TESLIM, Durum))
print(len(Durum), [d.name for d in Durum])
print(Durum.TESLIM in Durum, 4 in Durum, 9 in Durum)
# çıktı: Durum.KARGODA
# çıktı: <Durum.KARGODA: 3>
# çıktı: KARGODA 3
# çıktı: Durum.HAZIRLANIYOR Durum.TESLIM
# çıktı: <enum 'Durum'> True
# çıktı: 4 ['BEKLIYOR', 'HAZIRLANIYOR', 'KARGODA', 'TESLIM']
# çıktı: True True FalseÇıktıları sırayla okuyalım. str() (ve print()) yalnızca sınıf ve üye adını, repr() ise değeri de gösterir: <Durum.KARGODA: 3>. Üyenin tipi Enum sınıfının kendisidir. Çağrı söz dizimi değere göre, köşeli parantez ada göre arar. Sınıf üzerinde yineleme üyeleri tanım sırasıyla verir ve len() üye sayısını döndürür. in işleci hem üyeleri hem değerleri kabul eder; belgelere göre Python 3.12 öncesinde üye olmayan bir değerle in denetimi TypeError veriyordu, artık True ya da False döndürüyor.
Geçersiz bir değer ya da ad aradığınızda alacağınız hatalar ve üyeleri değiştirme girişiminin sonucu:
from enum import Enum
class Renk(Enum):
KIRMIZI = 1
YESIL = 2
try:
Renk(7)
except ValueError as e:
print(e)
try:
Renk['MAVI']
except KeyError as e:
print('KeyError:', e)
try:
Renk.KIRMIZI = 5
except AttributeError as e:
print(e)
# çıktı: 7 is not a valid Renk
# çıktı: KeyError: 'MAVI'
# çıktı: cannot reassign member 'KIRMIZI'Kullanıcıdan ya da bir dosyadan gelen değeri Enum'a çevirirken bu ValueError'ı yakalamak, geçersiz girdiyi erken reddetmenin temiz bir yoludur. Hata yakalama kalıpları için try-except yazısına bakabilirsiniz.
Takma adlar ve @unique
Aynı adı iki kez tanımlamak hata verir, ama iki farklı adın aynı değeri taşıması serbesttir. Bu durumda ikinci ad yeni bir üye değil, ilk üyenin takma adıdır (alias): ada göre arandığında da değere göre arandığında da ilk üye döner. Yinelemede takma adlar görünmez; __members__ eşlemesi ise takma adlar dahil bütün adları içerir:
from enum import Enum, unique
class Sekil(Enum):
KARE = 2
BAKLAVA = 1
DAIRE = 3
KARE_TAKMA_AD = 2 # aynı değer: takma ad (alias)
print(Sekil.KARE_TAKMA_AD, Sekil(2))
print(list(Sekil))
print(list(Sekil.__members__))
print([ad for ad, uye in Sekil.__members__.items() if uye.name != ad])
try:
@unique
class Hata(Enum):
BIR = 1
IKI = 2
UC = 3
DORT = 3
except ValueError as e:
print(e)
# çıktı: Sekil.KARE Sekil.KARE
# çıktı: [<Sekil.KARE: 2>, <Sekil.BAKLAVA: 1>, <Sekil.DAIRE: 3>]
# çıktı: ['KARE', 'BAKLAVA', 'DAIRE', 'KARE_TAKMA_AD']
# çıktı: ['KARE_TAKMA_AD']
# çıktı: duplicate values found in <enum 'Hata'>: DORT -> UCTakma ad istemiyorsanız sınıfı @unique ile işaretleyin; tekrar eden bir değer bulunduğunda sınıf oluşturulmaz ve hangi adın hangisinin kopyası olduğu mesajda yazar. Daha ayrıntılı kısıtlar için @verify dekoratörü ve EnumCheck seçenekleri (UNIQUE, CONTINUOUS, NAMED_FLAGS) vardır. Python 3.13 ile çalışma anında takma ad eklemek için _add_alias_() ve _add_value_alias_() metotları geldi.
Karşılaştırma: Enum ve IntEnum farkı
Enum üyeleri kimlikle karşılaştırılır; her üye tekil bir nesnedir, bu yüzden is güvenle kullanılabilir. Eşitlik (==) tanımlıdır ama Enum olmayan değerlerle karşılaştırma her zaman False döner. Sıralama karşılaştırması ise desteklenmez. IntEnum bilerek farklı tasarlanmıştır: üyeleri int'in alt sınıfıdır, tam sayılarla karşılaştırılabilir, sıralanabilir ve tam sayı beklenen her yerde, örneğin liste indeksinde, kullanılabilir:
from enum import Enum, IntEnum
class Renk(Enum):
KIRMIZI = 1
MAVI = 3
class Oncelik(IntEnum):
DUSUK = 1
ORTA = 2
YUKSEK = 3
print(Renk.KIRMIZI is Renk.KIRMIZI, Renk.KIRMIZI == 1, Renk.KIRMIZI.value == 1)
try:
Renk.KIRMIZI < Renk.MAVI
except TypeError as e:
print(e)
print(Oncelik.YUKSEK > Oncelik.DUSUK, Oncelik.ORTA == 2, Oncelik.ORTA + 1)
print(sorted([Oncelik.YUKSEK, Oncelik.DUSUK]))
print(str(Oncelik.ORTA), f'{Oncelik.ORTA}', ['a', 'b', 'c'][Oncelik.DUSUK])
# çıktı: True False True
# çıktı: '<' not supported between instances of 'Renk' and 'Renk'
# çıktı: True True 3
# çıktı: [<Oncelik.DUSUK: 1>, <Oncelik.YUKSEK: 3>]
# çıktı: 2 2 bOncelik.ORTA + 1 sonucunun düz 3 olduğuna dikkat edin: belgelere göre bir IntEnum üyesiyle tam sayı işlemi yapıldığında sonuç Enum niteliğini kaybeder. Python 3.11'den beri IntEnum'un str() sonucu da int'inki gibidir ('2'); amaç, var olan tam sayı sabitlerinin yerine sorunsuz geçebilmesidir. Genel öneri: değerin sayı olarak kullanılması gerçekten gerekmiyorsa düz Enum tercih edin, çünkü yanlışlıkla sayıyla karşılaştırma gibi hataları yakalar.
auto() ve StrEnum
Değerin ne olduğu önemli değilse auto() uygun değeri sizin yerinize seçer. Düz Enum ve IntEnum'da 1'den başlayıp artan tam sayılar, Flag ve IntFlag'de 1'den başlayan ikinin kuvvetleri, StrEnum'da ise üye adının küçük harfli hâli üretilir. Python 3.13'ten beri sonraki değer, son görülen değere göre değil, görülen en yüksek değere göre hesaplanıyor. Değer üretimini _generate_next_value_ statik metoduyla özelleştirebilirsiniz; bu metot üyelerden önce tanımlanmalıdır.
from enum import Enum, StrEnum, auto
import json
class Yon(Enum):
KUZEY = auto()
GUNEY = auto()
DOGU = auto()
class Ortam(StrEnum):
GELISTIRME = auto()
CANLI = auto()
print([y.value for y in Yon])
print(repr(Ortam.CANLI), str(Ortam.CANLI))
print(Ortam.CANLI == 'canli', Ortam('gelistirme'))
print(json.dumps({'ortam': Ortam.CANLI}))
print(f'/etc/uygulama/{Ortam.CANLI}.conf')
# çıktı: [1, 2, 3]
# çıktı: <Ortam.CANLI: 'canli'> canli
# çıktı: True gelistirme
# çıktı: {"ortam": "canli"}
# çıktı: /etc/uygulama/canli.confStrEnum üyeleri str'nin alt sınıfı olduğu için metinle karşılaştırılabilir, f-string içinde doğrudan değerleriyle yazılır ve json.dumps() tarafından düz metin olarak serileştirilir. Yapılandırma dosyalarındaki ortam adları, HTTP yöntemleri ya da dosya uzantıları için pratik bir seçimdir. Belgelerin uyarısı: standart kütüphanede tam olarak str tipi bekleyen (type(x) == str) yerler vardır, oralarda str(Uye) ile çevirmeniz gerekir. JSON ayrıntıları için json modülü yazısına bakabilirsiniz.
Flag ve IntFlag: bit bayrakları

Flag üyeleri &, |, ^ ve ~ işleçleriyle birleştirilebilir ve sonuç yine aynı Flag tipinden olur. Değerler ikinin kuvveti olmalıdır; auto() bunu kendiliğinden sağlar. Birleşimin içinde bir bayrağın olup olmadığı in ile denetlenir, birleşim üzerinde yinelemek içerdiği tekil bayrakları verir. IntFlag ayrıca int gibi davranır; Unix dosya izinleri gibi sayısal bayraklar için uygundur:
from enum import IntFlag, Flag, auto
class Izin(IntFlag):
R = 4
W = 2
X = 1
rw = Izin.R | Izin.W
print(repr(rw), int(rw))
print(Izin.R in rw, Izin.X in rw)
print(list(rw))
print(repr(Izin.R & Izin.X), bool(Izin.R & Izin.X))
print(repr(Izin(7)), str(Izin(7)), Izin.R + 1)
class Gun(Flag):
PZT = auto()
SAL = auto()
CAR = auto()
CMT = auto()
PAZ = auto()
HAFTASONU = CMT | PAZ
print([g.value for g in Gun])
print(Gun.CMT in Gun.HAFTASONU, repr(Gun.PZT | Gun.CAR))
# çıktı: <Izin.R|W: 6> 6
# çıktı: True False
# çıktı: [<Izin.R: 4>, <Izin.W: 2>]
# çıktı: <Izin: 0> False
# çıktı: <Izin.R|W|X: 7> 7 5
# çıktı: [1, 2, 4, 8, 16]
# çıktı: True <Gun.PZT|CAR: 5>Hiçbir bayrağın seçili olmadığı birleşim (<Izin: 0>) yanlış (False) sayılır; düz Enum üyeleri ise her zaman doğrudur. Sınıf içinde birleşimlere ad verebilirsiniz (HAFTASONU = CMT | PAZ); bu adlar takma ad sayılır ve yinelemede görünmez. IntFlag'in str() sonucunun da sayı olduğuna, toplama gibi bit dışı işlemlerin sonucun Flag niteliğini kaldırdığına dikkat edin. Geçersiz değerlerle ne yapılacağı FlagBoundary ayarına (STRICT, CONFORM, EJECT, KEEP) bağlıdır.
| Tür | Taban | Sayı/metinle == | Sıralama | auto() değeri |
|---|---|---|---|---|
| Enum | Enum | Hayır (her zaman False) | Yok | 1, 2, 3... |
| IntEnum | int ve Enum | Evet | Var | 1, 2, 3... |
| StrEnum | str ve Enum | Evet | Metin sıralaması | Küçük harfli üye adı |
| Flag | Enum | Hayır | Yok | 1, 2, 4, 8... |
| IntFlag | int ve Flag | Evet | Var | 1, 2, 4, 8... |
Enum'a metot, öznitelik ve özel davranış eklemek
Python Enum'ları yalnızca ad-değer çiftleri değildir; sıradan sınıflar gibi metot, classmethod ve property taşıyabilir. Metot içinde self üyenin kendisidir. Üye değeri bir demet olduğunda ve sınıf __init__ tanımladığında, demetin elemanları ayrı argümanlar olarak __init__'e iletilir. Belgelerdeki gezegen örneğinin kargo seçeneklerine uyarlanmış hâli:
from enum import Enum
class Kargo(Enum):
STANDART = (3, 49.90)
HIZLI = (1, 89.90)
def __init__(self, gun, ucret):
self.gun = gun
self.ucret = ucret
@property
def aciklama(self):
return f'{self.name.title()}: {self.gun} gün, {self.ucret} TL'
@classmethod
def en_ucuz(cls):
return min(cls, key=lambda k: k.ucret)
print(Kargo.HIZLI.value)
print(Kargo.HIZLI.aciklama)
print(Kargo.en_ucuz())
print(Kargo((1, 89.90)))
# çıktı: (1, 89.9)
# çıktı: Hizli: 1 gün, 89.9 TL
# çıktı: Kargo.STANDART
# çıktı: Kargo.HIZLIBelgelere göre üyenin değerini değiştirmek istiyorsanız (örneğin demetin yalnızca ilk elemanını değer yapmak) __new__ gerekir ve içinde _value_ atanır; diğer her türlü özelleştirme için __init__ tercih edilir. Hangi adların üye olacağı da kurallıdır: tek alt çizgiyle başlayıp biten adlar Enum'a ayrılmıştır, özel metotlar, betimleyiciler (metotlar dahil) ve _ignore_ listesindeki adlar üye olmaz, geri kalan her atama üye olur. Python 3.11 ile _Ozel__ad biçimindeki karıştırılmış adlar da üye sayılmıyor.
_missing_ ile esnek arama
Değere göre arama bulunamadığında Python _missing_ sınıf metodunu çağırır. Varsayılanı hiçbir şey yapmaz, ama onu geçersiz kılarak büyük/küçük harf duyarsız arama ya da eski değerleri yeni üyelere eşleme gibi kurallar yazabilirsiniz. Metot bir üye döndürürse arama başarılı sayılır, None döndürürse olağan ValueError oluşur:
from enum import StrEnum, auto
class Seviye(StrEnum):
DEBUG = auto()
INFO = auto()
@classmethod
def _missing_(cls, deger):
deger = deger.lower()
for uye in cls:
if uye.value == deger:
return uye
return None
print(Seviye('INFO'), repr(Seviye('Debug')))
try:
Seviye('trace')
except ValueError as e:
print(e)
# çıktı: info <Seviye.DEBUG: 'debug'>
# çıktı: 'trace' is not a valid SeviyeFonksiyonel API, alt sınıf kuralı ve match
Enum sınıfı çağrılabilir: Enum('Hayvan', 'KEDI KOPEK KUS') aynı adlı sınıf söz dizimiyle eşdeğer bir Enum oluşturur. İkinci argüman boşlukla ya da virgülle ayrılmış adlar, ad listesi, (ad, değer) çiftleri ya da bir sözlük olabilir; değer verilmezse 1'den başlanır. Belgeler 0 yerine 1'den başlanmasının nedenini de açıklar: 0 mantıksal olarak yanlıştır, Enum üyeleri ise varsayılan olarak doğru sayılır. Fonksiyonel API ile oluşturulan Enum'ları pickle ile serileştirmek için module=__name__ vermeniz önerilir.
from enum import Enum
Hayvan = Enum('Hayvan', 'KEDI KOPEK KUS')
print(list(Hayvan))
class Renk(Enum):
KIRMIZI = 1
try:
class DahaFazlaRenk(Renk):
PEMBE = 17
except TypeError as e:
print(e)
class Davranis(Enum): # üyesiz enum: ortak davranış
def etiket(self):
return self.name.lower()
class Boyut(Davranis):
KUCUK = 1
BUYUK = 2
print(Boyut.BUYUK.etiket())
def ucret(boyut):
match boyut:
case Boyut.KUCUK:
return 10
case Boyut.BUYUK:
return 25
print(ucret(Boyut.BUYUK))
# çıktı: [<Hayvan.KEDI: 1>, <Hayvan.KOPEK: 2>, <Hayvan.KUS: 3>]
# çıktı: <enum 'DahaFazlaRenk'> cannot extend <enum 'Renk'>
# çıktı: buyuk
# çıktı: 25Üyesi olan bir Enum'dan türetme yapılamaz; buna izin verilseydi tiplerle örnekler arasındaki bazı temel değişmezler bozulurdu. Ortak davranışı paylaşmanın yolu, üyesiz bir taban Enum'da metotları tanımlayıp üyeleri alt sınıfa koymaktır. Enum üyeleri match deyiminde noktalı adlarla (case Boyut.KUCUK:) değer deseni olarak kullanılabilir; ayrıntılar match-case yazısında. Dataclass ile Enum'un birlikte kullanımı 3.12'de desteklendi; değer olarak dataclass kullanmak için dataclasses yazısına bakabilirsiniz.
İki pratik ayrıntı daha. Enum üyeleri pickle ile serileştirilip geri yüklendiğinde aynı üye nesnesine döner; ancak bunun için Enum'un bir modülün en üst düzeyinde tanımlı olması gerekir, çünkü geri yükleme sınıfın o modülden içe aktarılabilmesine dayanır. Varsayılan serileştirme değere göredir. İkincisi doğruluk değeri: düz Enum üyeleri, değerleri 0 bile olsa her zaman doğru sayılır. Üyenin doğruluğunun değerine bağlı olmasını istiyorsanız belgelerin önerdiği gibi sınıfa def __bool__(self): return bool(self.value) ekleyin. int ya da str ile karışan Enum'lar ise karıştıkları tipin kurallarına uyar.
Sık yapılan hatalar

- Üyeyi değeriyle karşılaştırmak:
durum == 3düz Enum'da her zamanFalsedöner.durum is Durum.KARGODAya dadurum.value == 3yazın. - Enum değerini sıralamaya çalışmak: Düz Enum'da
<desteklenmez. Sıra gerekiyorsaIntEnumkullanın ya dasorted(..., key=lambda u: u.value)ile değere göre sıralayın. - Üyeyi değiştirmeye çalışmak:
Renk.KIRMIZI = 5AttributeErrorverir; üyeler sabittir. - Üyeli Enum'dan türetmek:
TypeErrorverir; ortak davranışı üyesiz taban Enum'a koyun. - Flag değerlerini elle yanlış seçmek: 1, 2, 3 gibi ikinin kuvveti olmayan değerler bayrakları birbirine karıştırır;
auto()kullanın. - Modül yeniden yüklemesi: Belgeler, Enum içeren bir modül yeniden yüklendiğinde yeni üyelerin eskilerle aynı nesne ya da eşit olmayabileceğini uyarır.
Sık Sorulan Sorular
Enum değerini veritabanına ya da JSON'a nasıl yazarım?
Düz Enum'da uye.value ya da uye.name değerini yazıp okurken Durum(deger) veya Durum[ad] ile geri çevirin. StrEnum ve IntEnum üyeleri zaten metin ve sayı oldukları için doğrudan serileştirilebilir. Veritabanı tarafı için sqlite3 yazısına bakabilirsiniz.
Enum üyelerini liste olarak nasıl alırım?
list(Durum) takma adlar hariç üyeleri tanım sırasıyla verir. Adlar için [u.name for u in Durum], takma adlar dahil her şey için Durum.__members__ kullanılır.
auto() ile verilen değerler program her çalıştığında aynı mı?
Evet. Değerler tanım sırasına göre belirlenir ve _generate_next_value_ değiştirilmedikçe aynı kalır. Yine de değer kalıcı olarak saklanacaksa (veritabanı, dosya) sınıfın ortasına yeni üye eklemenin sonraki değerleri kaydıracağını unutmayın; böyle durumlarda değerleri açıkça yazmak daha güvenlidir.
Enum ile sabit bir sözlük arasındaki fark nedir?
Sözlük değiştirilebilir ve anahtarları sıradan metinlerdir. Enum üyeleri ise değiştirilemez, tekil nesnelerdir, kendi tiplerine sahiptir ve metot taşıyabilir. Seçenek kümesi sabitse Enum, çalışma anında değişen eşlemeler için sözlük daha uygundur.
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 · Class ve nesne · dataclasses · match-case · json modülü