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.