DEV Community

Julio Oliveira
Julio Oliveira

Posted on • Originally published at oliveira-julio.github.io

Why use Enums instead simple primitive types

Some data value use a basic type like str or int,
but not all str and int are valid values of that data value.
Enums can limit the possibilities to only a defined set of values.

Example:

Blood type is a string, but have a set of only 8 valid strings.
Don't exist a blood called 'randombloodtype' but 'AB-' is valid.

from enum import Enum

class BloodType(str, Enum):
    A_negative = "A-"
    B_negative = "B-"
    AB_negative = "AB-"
    O_negative = "O-"
    A_positive = "A+"
    B_positive = "B+"
    AB_positive = "AB+"
    O_positive = "O+"

assert "A-" in list(BloodType)
assert "O+" == BloodType.O_positive
Enter fullscreen mode Exit fullscreen mode

So why not just use list?

The below code do the same as the above:

BLOOD_TYPE = [
    "A-",
    "B-",
    "AB-",
    "O-",
    "A+",
    "B+",
    "AB+",
    "O+",
]

assert "A-" in BLOOD_TYPE
Enter fullscreen mode Exit fullscreen mode

But let us suppose we should make a new piece of code. Given the donor blood type, returns the list of allowed recipients.

from typing import List

def blood_type_can_donate_to(donor: str) -> List[str]:
    _recipients = {
        "A-": ["A-", "AB-", "A+", "AB+"],
        "B-": ["B-", "AB-", "B+", "AB+"],
        "AB-": ["AB-", "AB+"],
        "O-": ["A-","B-", "AB-", "O-", "A+", "B+", "AB+", "0+"],
        "A+": ["A+", "AB+"],
        "B+": ["B+", "AB+"],
        "AB+": ["AB+"],
        "O+": ["A+", "B+", "AB+", "O+"]
    }
    return _recipients[donor]
Enter fullscreen mode Exit fullscreen mode

And using enum:

from enum import Enum
from typing import List

class BloodType(str, Enum):
    A_negative = "A-"
    B_negative = "B-"
    AB_negative = "AB-"
    O_negative = "O-"
    A_positive = "A+"
    B_positive = "B+"
    AB_positive = "AB+"
    O_positive = "O+"

def blood_type_can_donate_to(donor: BloodType) -> List[BloodType]:
    if donor == BloodType.A_negative:
        return [
            BloodType.A_negative,
            BloodType.AB_negative,
            BloodType.A_positive,
            BloodType.AB_positive
        ]
    elif donor == BloodType.B_negative:
        return [
            BloodType.B_negative,
            BloodType.AB_negative,
            BloodType.B_positive,
            BloodType.AB_positive
        ]
    elif donor == BloodType.AB_negative:
        return [
            BloodType.AB_negative,
            BloodType.AB_positive
        ]
    elif donor == BloodType.O_negative:
        return list(BloodType)
    elif donor == BloodType.A_positive:
        return [
            BloodType.A_positive,
            BloodType.AB_positive
        ]
    elif donor == BloodType.B_positive:
        return [
            BloodType.B_positive,
            BloodType.AB_positive
        ]
    elif donor == BloodType.AB_positive:
        return [
            BloodType.AB_positive
        ]
    elif donor == BloodType.O_positive:
        return [
            BloodType.A_positive,
            BloodType.B_positive,
            BloodType.AB_positive,
            BloodType.O_positive
        ]
Enter fullscreen mode Exit fullscreen mode

The second one does exactly the same as the first one, but have some big advantages:

  • Help you to avoiding mistakes.
  • Help to code editor to warning if you make a mistake.
  • Help to the next person to works in the code, avoid mistakes.

See the first version again: It has a typo error, a 0 instead of a O.

Top comments (2)

Collapse
 
mcsee profile image
Maxi Contieri

You polute you code with large functions and several IFs.

The besto solution, IMHO is to use objects instead of enums

Collapse
 
oliveirajulio profile image
Julio Oliveira

Thank you for reading my post.
I wrote a version without using ifs, using the dict like in the first code block. But the code formatting in the final article don't looks goods, so i changed.
Python pattern matching can be a better solution too, but is too new. I think can confuse beginners.