Výčtový typ

Výčtový typ (Enum) slouží k výčtu nějakého konečného počtu hodnot. Například názvy dnů v týdnu, výčet barev, typů platby na nějakém platebním portálu atp. Python podporuje Enum až od verze 3.4, takže tato kapitola se Pythonu 2.7 netýká.

Enum

Výčtový typ se vytváří děděním z enum.Enum, tj. z třídy Enum z modulu enum. Moduly budou popsány v jedné z dalších kapitol. Prozatím vám stačí vědět, že musíte Enum importovat pomocí řádky from enum import Enum.

from enum import Enum

class Barvy(Enum):
     red = "Cervena"
     blue = "#0000FF"
     black = 0

red, blue a black v příkladu jsou jména, kterým jsou přiřazeny (za rovnítkem) nějaké hodnoty.

Jak vidíte v příkladu, hodnota může být různého typu. Použití různých typů není ale obvykle dobrý nápad a hodnota výčtového typu vás ani většinou nezajímá. Rozumější příklad může vypadat takto:

from enum import Enum

class DenTydnu(Enum):
    po = 1
    ut = 2
    st = 3
    ct = 5
    pa = 6
    so = 7
    ne = 8

Výčtový typ není lecjaká obyčejná třída. Má několik speciálních vlastností.

Třída výčtového typu je iterovatelná:

>>> list(DenTydnu)
[<DenTydnu.po: 1>, <DenTydnu.ut: 2>, <DenTydnu.st: 3>, <DenTydnu.ct: 5>, <DenTydnu.pa: 6>, <DenTydnu.so: 7>, <DenTydnu.ne: 8>]

Členy výčtového typu mají jen jednu instanci (můžete se spolehnout na operátor is):

>>> DenTydnu.po = 100
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.4/enum.py", line 292, in __setattr__
    raise AttributeError('Cannot reassign members.')
AttributeError: Cannot reassign members.

Člen výčtového typu je potomkem svého výčtového typu:

>>> isinstance(DenTydnu.po, DenTydnu)
True

Člen výčtového typu je třída, která má atributy name a value.
Člen výčtového typu se nerovná své hodnotě!

DenTydnu.po == 1
False
>>> DenTydnu.po.value == 1
True
>>> DenTydnu.po.name
'po'

Z toho taky plyne, že výčtové typy můžete porovnávat na rovnost a nerovnost, ale ne na "větší" a "menší".

>>> DenTydnu.po == DenTydnu.ut
False
>>> DenTydnu.po > DenTydnu.ut
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: DenTydnu() > DenTydnu()

Členové dvou výčtových typů se sobě nerovnají, ikdyž mají stejnou hodnotu:

class Mesic(Enum):
    le = 1
    un = 2
    br = 3
    du = 4
    ...
>>> Mesic.le == DenTydnu.po
False
>>> Mesic.le.value == DenTydnu.po.value
True

IntEnum

Výčtový typ může také dědit z enum.IntEnum. V takovém případě jsou členové výčtového typu také potomky int, tj. můžete s nimi zacházet jako s čísly.

from enum import IntEnum

class DenTydnu(IntEnum):
    po = 1
    ut = 2
    st = 3
    ct = 5
    pa = 6
    so = 7
    ne = 8

class Mesic(IntEnum):
    le = 1
    un = 2
    br = 3
    du = 4
    ...
>>> DenTydnu.po < DenTydnu.ut
True
>>> DenTydnu.po == Mesic.le
True
>>> DenTydnu.po == 1
True
>>> den = DenTydnu.ut
>>> print(["Pondeli","Uteri","Streda"][den-1])
Uteri
>>> list(DenTydnu)
[<DenTydnu.po: 1>, <DenTydnu.ut: 2>, <DenTydnu.st: 3>, <DenTydnu.ct: 5>, <DenTydnu.pa: 6>, <DenTydnu.so: 7>, <DenTydnu.ne: 8>]
>>> DenTydnu.po.value
1
>>> DenTydnu.po.name
'po'

Je doporučováno používat Enum spíše než IntEnum, právě kvůli tomu, že se IntEnum chová spíše jako číslo než jako Enum (můžete ho porovnávat s jiným číslem nebo s jiným IntEnum členem, na nerovnost). Většinou je špatně, že se pondělí rovná lednu …

Komentář Hlášení chyby
Created: 30.8.2015
Last updated: 30.8.2015