What advantage does using an Enum bring if it's not encoding underlying values?

500 Views Asked by At

EDIT: I've heavily edited this question from the original, to focus on the advantages of Enum in this case (the question had been put on hold for being primarily opinion-based)


I understand the sense of using an Enum when it's converting a human-readable string into an underlying (e.g. numeric) value, with the FederalHoliday class in this answer being a good example of that.

But the use-case I'm considering is just where a function parameter is restricted to a set of possible values, which are currently passed as "magic strings". So implementing an Enum here wouldn't really improve code readability (if anything, it would make the code more cluttered). And turning a string into an Enum, only to compare on what is effectively the same string (i.e. the name of the Enum) feels like overkill.

This answer has a fantastic list of general advantages of enums, but I'm not sure how many of them apply in this case.

To clarify the case I'm meaning, there is an example of it here, with a function that prints a string with certain capitalization as specified by mode:

def print_my_string(my_string, mode):
    if mode == 'l':
        print(my_string.lower())
    elif mode == 'u':
        print(my_string.upper())
    elif mode == 'c':
        print(my_string.capitalize())
    else:
        raise ValueError("Unrecognised mode")

To see this in action, running this:

for mode in ['l', 'u', 'c']:
    print_my_string("RaNdoM CAse StRING", mode)

gives:

random case string
RANDOM CASE STRING
Random case string

So my question is:

What advantage does an Enum bring when the strings don't represent another value underneath? Is there any way that it makes the code more robust?


Other things I've read:

Mainly about Enums in general, especially when the strings represent another value underneath:

This seems to have an example similar to mine (under Enums are interoperable), but I struggled to understand the technical discussion around it, and it only shows setting the Enum, not using it:


EDIT: In this case it'd be possible to map the strings directly to the function they correspond to, but this isn't possible in my actual use case as the code is more complicated. (But it's a good tip from those who suggested it in the comments.)

1

There are 1 best solutions below

2
On

I don't know whether my way is pythonic. But I may use this way:

string_mode = {
    'l': lambda s: s.lower(),
    'u': lambda s: s.upper(),
    'c': lambda s: s.capitalize(),
    't': lambda s: s.title(),
    's': lambda s: s.swapcase()
}

for mode in string_mode:
    print(string_mode.get(mode, lambda s: s)("RaNdoM CAse StRING"))

According to the comment of @Yakym Pirozhenko, we can use a more pythonic way to do this:

string_mode = {
    'l': str.lower,
    'u': str.upper,
    'c': str.capitalize,
    't': str.title,
    's': str.swapcase
}

for mode in string_mode:
    print(string_mode.get(mode, lambda s: s)("RaNdoM CAse StRING"))

Moreover, we can use a function, too:

def string_mode(string, mode='default'):
    return {
        'l': str.lower,
        'u': str.upper,
        'c': str.capitalize,
        't': str.title,
        's': str.swapcase
    }.get(mode, lambda s:s)(string)