När en status i en webbapp kan vara "draft", "published" eller "archived" räcker en felstavad sträng för att skapa ett svårfunnet fel. En Enum ger statusen ett fast antal namngivna värden, men valet mellan vanlig Enum och dess sträng- eller heltalsvarianter beror på hur värdet ska användas utanför Python.

Välj enum-typ efter hur värdet ska användas
- Enum passar när värdena ska vara tydligt avgränsade och inte bete sig som vanliga strängar eller tal.
- StrEnum passar när värdena behöver fungera som strängar, exempelvis i JSON eller API-anrop.
- IntEnum är främst till för kompatibilitet med äldre kod eller system som kräver heltal.
- Flag används när flera alternativ kan kombineras, till exempel behörigheter.
- Alias kan uppstå när två medlemmar får samma värde; dekoratören
@uniquestoppar det.
En Enum gör tillåtna statusar tydliga
En status som skickas runt som vanlig text kan råka få flera stavningar: "published", "Publish" eller "publised". Med en enum samlas de giltiga valen på ett ställe, och koden använder namngivna medlemmar i stället för lösa strängar.
from enum import Enum
class PageStatus(Enum):
DRAFT = "draft"
PUBLISHED = "published"
ARCHIVED = "archived"
status = PageStatus.PUBLISHED
if status is PageStatus.PUBLISHED:
print("Sidan visas")Medlemmarna är egna enum-objekt. Därför är PageStatus.PUBLISHED inte samma sak som strängen "published"; använd status.value när själva värdet behövs. Jag tycker att vanlig Enum är det säkraste standardvalet när du vill att fel typ ska märkas tydligt.
StrEnum och IntEnum passar när kompatibilitet krävs
Problemet börjar ofta vid gränsen till ett API, en databas eller äldre kod. Om mottagaren kräver en vanlig sträng kan StrEnum låta enum-medlemmarna användas i många strängsammanhang, medan IntEnum gör medlemmarna kompatibla med heltal.
| Typ | Passar när | Se upp med |
|---|---|---|
Enum | Du vill ha avgränsade värden som inte likställs med vanliga strängar eller tal. | Konvertera till .value där ett externt gränssnitt kräver råvärdet. |
StrEnum | Enum-värden ska användas som strängar. | Vissa bibliotek kontrollerar exakt typ med type(x) == str; då kan str(member) behövas. |
IntEnum | Äldre kod eller ett externt system kräver numeriska konstanter. | Medlemmarna kan jämföras med vanliga heltal, vilket gör typgränsen mindre strikt. |
StrEnum lades till i Python 3.11. Enligt Python-dokumentationen för enum kan vissa funktioner kräva exakt typen str i stället för en underklass, så provkör serialisering och tredjepartsbibliotek innan du byter typ.
Värdena behöver inte vara unika om du tillåter alias
Två namn med samma värde är tillåtna i en enum, men det andra namnet blir då ett alias för det första. Därför är det missvisande att anta att varje rad i en enum automatiskt ger en separat medlem.
from enum import Enum, unique
@unique
class PageStatus(Enum):
DRAFT = "draft"
PUBLISHED = "published"
LIVE = "published" # ValueErrorHär hindrar @unique att LIVE tyst blir ett extra namn för PUBLISHED. I Python-dokumentationens Enum HOWTO beskrivs även hur name och value skiljer sig: använd det första för medlemsnamnet och det andra för det tilldelade värdet.
Välj Flag när flera val ska kunna kombineras
En vanlig enum representerar normalt ett val åt gången. Om en användare däremot kan ha flera behörigheter samtidigt, som läsa och redigera, passar Flag bättre eftersom medlemmar kan kombineras med bitvisa operatorer.
from enum import Flag, auto
class Permission(Flag):
READ = auto()
EDIT = auto()
DELETE = auto()
access = Permission.READ | Permission.EDIT
if Permission.EDIT in access:
print("Redigering tillåten")Flag håller kombinationen inom enum-typen. Välj IntFlag i stället om kombinationerna också måste fungera som heltal; vanlig aritmetik kan dock göra att resultatet inte längre är en enum-medlem.
Följ den här tumregeln när du väljer
Tänk på var värdet ska landa. Om det stannar i Python och ska uttrycka ett avgränsat alternativ, välj Enum; om ett gränssnitt kräver strängar eller heltal, välj motsvarande blandtyp; om alternativen ska kombineras, använd Flag.
| Situation | Trolig orsak eller följd | Gör så här |
|---|---|---|
Jämförelse med "published" misslyckas | Du jämför en vanlig Enum-medlem med dess råa strängvärde. | Jämför med PageStatus.PUBLISHED eller använd status.value där en sträng behövs. |
En enum-medlem skickas till ett bibliotek som kräver exakt str | StrEnum är en underklass av str, men biblioteket kan kontrollera typen strikt. | Prova str(member) vid just den gränsen. |
| Behörigheter ska kunna väljas i kombination | Flera oberoende flaggor behöver representeras samtidigt. | Använd Flag eller IntFlag, inte en vanlig enum. |
| Två namn verkar peka på samma alternativ | Medlemmarna har fått identiska värden och ett alias har skapats. | Lägg till @unique om varje värde ska ha ett enda namn. |
För en webbplatsstatus som bara hanteras i Python skulle jag välja vanlig Enum; om samma värde måste skickas som text i ett API skulle jag välja StrEnum och kontrollera hur API-klienten hanterar typen. Den lilla skillnaden i definition kan förebygga en större felsökning vid systemgränsen.
Håll råvärdet stabilt när data sparas
En enum kan göra intern kod tydligare, men när värden sparas i en databas eller skickas över nätet blir de en del av ett gränssnitt. Välj därför värden med eftertanke och byt inte exempelvis "published" mot "live" utan att kontrollera befintlig lagring och konsumenter.
En enkel tumregel håller långt: använd Enum för strikt intern modellering, StrEnum eller IntEnum när kompatibilitet krävs, och Flag när flera val kan gälla samtidigt.