
Using Enumerated Types in Python - kaunta
https://johnlekberg.com/blog/2020-06-06-enum.html
======
elcomet
Enums are best when combined with a language that does pattern matching and
that can warn you if you forgot a value in your case statement. Python lacks
this, so there is no spectacular benefit of using enums over just a list of
strings.

~~~
zo1
The article is incredibly misleading. Python Enums are way more powerful than
what is showcased there.

First, rudimentary/basic enums are as simple as instance variables on a class
and allow super-helpful IDE "auto-completion" that doesn't necessitate the use
of magic-strings to at least "set" the enum. I've been using this ridiculously
simple trick since 2.5 ten years ago. Magic-strings are bad, and even worse
when you have a disparate code-base in a dynamically typed language. Example:

    
    
        class MyEnum(object):
            Pass = 1
            Fail = 2
    
        my_value = MyEnum. <-- at this point, the IDE gives you code-completion.
    
    

Second, real Enums added as a language-feature along with type-hinting are
almost 100% on-par with statically typed languages. See:

    
    
        class MyEnum(Enum):
            Pass = 1
            Fail = 2
    
        def my_func(did_they_pass: MyEnum):
            if did_they_pass.Something:   # IDE / type-checker will go nuts here.
                print("Something")
    

Edit: Forgot the main point. Switch/case uses are only a small sub-set of the
uses of Enums. So even basic/crappy enums are better than magic strings in a
dynamically-typed language. Also, please don't use "list of strings" for enums
in Python, there are much better ways to do that sort of thing that preclude
unnecessary bugs popping up.

~~~
BiteCode_dev
So, you don't use open("w"), do you ? You use the non magic open(os.O_WRONLY)
of course.

Because magic strings are bad.

~~~
MikeTheGreat
I will now - thanks for the tip! :)

And, moreover, this will inspire me to ask "How many other traditional magic
numbers/strings/etc have I gotten used to that might be defined more
readably?" strcmp, I'm looking at you!

I know your post was sarcastic/snarky but it was genuinely helpful

~~~
1wd
f.tell(offset, os.SEEK_CUR) over f.tell(offset, 1)

[https://docs.python.org/3/library/os.html#os.SEEK_CUR](https://docs.python.org/3/library/os.html#os.SEEK_CUR)

I wish the docs on f.tell at least mentioned the option

[https://docs.python.org/3/tutorial/inputoutput.html#methods-...](https://docs.python.org/3/tutorial/inputoutput.html#methods-
of-file-objects)

------
gorgoiler
It always feels a little clumsy when these class generators require the name
of the identifier to which they are assigned.

    
    
      Clown = circus.Actor(“Clown”)
    

Why is it needed, instead of just creating an anonymous class?

    
    
      Clown = circus.Actor()
    

Or allowing the class factory to manipulate the current namespace?

    
    
      circus.Actor(“Clown”)
      bozo = Clown()
    

I feel like I am perilously close to answering my own question, but not close
enough. I’m sure there’s a good reason, but I don’t know enough of the Python
internals to figure it out.

~~~
nemetroid
> Why is it needed, instead of just creating an anonymous class?

I think the question should be: why do you want an anonymous class? If it's
sufficiently ad-hoc that it doesn't warrant a name, you would typically use a
dict.

> Or allowing the class factory to manipulate the current namespace?

I think that would just be considered too surprising and non-standard
behaviour (other Python functions don't get to modify the scope they're called
from).

~~~
gorgoiler
Named tuples, the example I called out, are a good improvement over dicts for
adhoc structs that don’t require full class definitions.

But you’re right. It’s hardly cumbersome to create classes that simply exist
to contain data in a sightly more structured way than a dict.

~~~
nemetroid
> Named tuples, the example I called out, are a good improvement over dicts
> for adhoc structs that don’t require full class definitions.

Doesn't a lot of that improvement come from the fact that they have a name,
though? I guess you could argue for an "UnnamedTuple" which only enforces
tuple size and member names. But if you're able to specify the member names,
it feels like the thing being represented is concrete enough that you should
be able to come up with a name for it, and that having a name would be
beneficial.

------
NicoJuicy
Recently I started to use enumeration classes instead of enums ( where it
fits)

[https://docs.microsoft.com/en-
us/dotnet/architecture/microse...](https://docs.microsoft.com/en-
us/dotnet/architecture/microservices/microservice-ddd-cqrs-
patterns/enumeration-classes-over-enum-types)

If you develop in c#, I would definitely recommend trying it out

A better example can be found here actually:
[https://lostechies.com/jimmybogard/2008/08/12/enumeration-
cl...](https://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/)

~~~
nerdponx
What's the basic idea here? That instead of ints or strings, your enum values
themselves are instances of custom classes with whatever behavior you want?

~~~
NicoJuicy
If I would describe the use-case:

If you use switches with enums for functionality, this is a better way (
personal opinion). Since Enums quickly need more than 1 switch and this could
wrap that behaviour

Your description is also pretty good

------
ramraj07
Have constantly struggled over how to deal with this problem. The biggest need
for enums has been function arguments which can be one of a few values.

In the end, the Literal class from the typing library seems like the simplest,
least wordy solution. Pycharm and mypy capture any mistakes you make which
seem more than sufficient for my use cases.

~~~
nerdponx
Why not use Enum anyway, which works fine with MyPy? I don't mind the
verbosity, it's a one-time commitment to what, 10 extra lines of code?

~~~
ramraj07
Issue is I'll now need two imports everytime I call this method, which becomes
mildly annoying. I was doing this, but a lot of times the Literal type seems
more than sufficient. It also seems to play real nice with pydantic so it's an
added win!

~~~
nerdponx
I'm not sure what you mean by "two imports".

If you define your Enum subclass in the same file, you use one import for
enum.Enu. If you eschew enums and use Literal, you use one import for
typing.Literal.

------
danthemanvsqz
Prefer using named tuples over enums in Python.

~~~
wk_end
Named tuples and enums do entirely different things (loosely-speaking: the
former are product types, the latter are sum types).

You also probably want dataclasses [1] instead of named tuples.

[1]
[https://docs.python.org/3/library/dataclasses.html](https://docs.python.org/3/library/dataclasses.html)

~~~
danthemanvsqz
They do different things but in the wild are used in the same way. Data
classes are not immutable so it would not be ideal for what I used named
tuples for.

~~~
wk_end
Data classes can be made immutable using ‘frozen=True’. It sucks that it’s not
default though.

Can you give an example of how you use enums and named tuples in the same way?
That just doesn’t seem to make a lot of sense to me, but maybe I’m missing
something.

