In earlier versions of Python that don't have StrEnum, you can use `class X(str, Enum)` to get the same behaviour. This might be relevant if you're using `typer`, where you can use enums to define possible choices for CLI options, and it requires the Enum to also be a str.
is there anything wrong with setting the same integer value for different attributes of the IntEnum inheriting class? I notice that if I print their values individually they are properly recognized but if I place them in a list variable and print it, they will be displayed both as being of the type that was defined first (evidently because they share a common value)
I know this might sound counter intuitive, but i have used the functional option for enum with a long list of values to create a class, and I find it helpful.
I can definitely see this being useful for the when the values don't matter, but not sure about otherwise. I haven't seen an example of it in real life though, so it might be much easier than I'm imagining.
If you want to set integer enums to start at a specific value (e.g. 0) but also use auto() then you can set the first value explicitly to 0 and then use auto() for the rest. You can start at any number. auto() will use the next highest value above the current maximum. auto() also works on Flag enums. I think it selects the next power of 2 greater than the current maximum value.
Another reason to not use auto() is if you ever need to produce a compact serialization, in which case giving each option a bytes string value will do the trick. This can be useful for communication across a network, saving some space in a save file, etc. I haven't tested it yet, but I suspect that deserialization from short bytes values will be faster than using long string names and dict access.
I think of them as a tidier version of bidirectional dictionaries that are also immutable. It's nice to be able provide a value to lookup a name which bidicts can do but they are mutable so less safe in certain cases. Plus you can do isinstance checks on enums...
my dataclasses usually contain an enum subclass, e.g. an `Action` dataclass that defines a `Type` enum and has a `_type` variable which is an instance of that enum
I am confused also. A dataclass stores multiple, mutable data points of any type. A tuple does the same, but for immutable data. An enum on the other hand is basically your own defined data type. It gives you a type (not a variable or container for variables) where only the values you define beforehand are valid. I use them everywhere, for state of my object as shown here, for a type of command sent (you can match-case enums to tidily define response behaviour), as flags.
I used to be a big fan of Enums, but not anymore. for large projects, ive noticed things can quickly go to enum hell where you have to figure out where an enum is defined to import it - which causes a lot of interdependency imports. what i have personally moved to is string literals - i feel it gives me most of the benefit without the complexity
This seems like the kind of thing that an IDE should be able to address? If you want some enum value to provide as input to something expecting a value from that enum type, shouldn’t the IDE be able to tell you where that class is defined, and let you import it? Maybe I misunderstand the issue you describe. Though, as a variation on the “use string literals”… what if there was a standard class like “Symb” or something, where you could say Symb(“some string literal”) and the resulting object would be hashable and would have Symb(“string a”) is Symb(“string a”) and they would only be == if the strings were equal, and such values would be immutable, and would not expose the string they come from except through __repr__ (which would return ‘Symb(“string a”)’ for example). This way you wouldn’t need to import the class extending Enum, only the class Symb (or whatever it would be called), but, unlike with string literals, there would be no temptation to do string operations on it. Hm, though, this doesn’t seem to facilitate a nice “does this case statement cover all the options of the enum” thing? Though maybe you could like, take a set of such things as serving a similar role as an Enum class? (Edit: this is in part inspired by lisp symbols)
for dynamic languages like python/js strings are fine. enums are really more powerful/necessary in compiled, statically-typed languages like java or c++
Plus, you can add string literals directly to type hints. But then you have the issue of propagating those parameters through to higher order calling functions. Maybe if you assigned a type alias to the collection of strings…. Wait, that’s just an enum again.
Seems more of a structural problem to me. Plus python allows you to import an import of your import, so this can also be pretty easy, if you are using a module that uses this enum. And now I need to make a "Yo Dawg" meme.
After rust, enums in other languages feel childish at best. Like what’s with myenum = 0. What does it even mean intuitively? C, go, … does it. And python has jumped onboard with something half-baked as usual. Pro-tip, like others have mentioned already, use dataclasses and your future self will thank you for it.
In earlier versions of Python that don't have StrEnum, you can use `class X(str, Enum)` to get the same behaviour. This might be relevant if you're using `typer`, where you can use enums to define possible choices for CLI options, and it requires the Enum to also be a str.
Fab explanation as always!
is there anything wrong with setting the same integer value for different attributes of the IntEnum inheriting class? I notice that if I print their values individually they are properly recognized but if I place them in a list variable and print it, they will be displayed both as being of the type that was defined first (evidently because they share a common value)
Wait. Python has Enums!?
😂
Yeah 😅
I take it you've never looked at the docs.
enumerator is not the same thing as an enumeration which is what enum stands for lol. Enumerator is more like the thing enumerate() returns
I know this might sound counter intuitive, but i have used the functional option for enum with a long list of values to create a class, and I find it helpful.
I can definitely see this being useful for the when the values don't matter, but not sure about otherwise. I haven't seen an example of it in real life though, so it might be much easier than I'm imagining.
If you want to set integer enums to start at a specific value (e.g. 0) but also use auto() then you can set the first value explicitly to 0 and then use auto() for the rest.
You can start at any number. auto() will use the next highest value above the current maximum.
auto() also works on Flag enums. I think it selects the next power of 2 greater than the current maximum value.
Oh nice, that's good to know!
Another reason to not use auto() is if you ever need to produce a compact serialization, in which case giving each option a bytes string value will do the trick. This can be useful for communication across a network, saving some space in a save file, etc. I haven't tested it yet, but I suspect that deserialization from short bytes values will be faster than using long string names and dict access.
I’m still somewhat confused about what Enums give us over dataclasses or namedtuples etc. Seems like it doesn’t really give us much
can you give an example where a dataclass/namedtuple has an advantage over enums?
I think of them as a tidier version of bidirectional dictionaries that are also immutable. It's nice to be able provide a value to lookup a name which bidicts can do but they are mutable so less safe in certain cases. Plus you can do isinstance checks on enums...
they are completely different things
my dataclasses usually contain an enum subclass, e.g. an `Action` dataclass that defines a `Type` enum and has a `_type` variable which is an instance of that enum
I am confused also. A dataclass stores multiple, mutable data points of any type. A tuple does the same, but for immutable data.
An enum on the other hand is basically your own defined data type. It gives you a type (not a variable or container for variables) where only the values you define beforehand are valid. I use them everywhere, for state of my object as shown here, for a type of command sent (you can match-case enums to tidily define response behaviour), as flags.
Can we make it a dataclass too?
I used to be a big fan of Enums, but not anymore. for large projects, ive noticed things can quickly go to enum hell where you have to figure out where an enum is defined to import it - which causes a lot of interdependency imports. what i have personally moved to is string literals - i feel it gives me most of the benefit without the complexity
This seems like the kind of thing that an IDE should be able to address?
If you want some enum value to provide as input to something expecting a value from that enum type, shouldn’t the IDE be able to tell you where that class is defined, and let you import it?
Maybe I misunderstand the issue you describe.
Though, as a variation on the “use string literals”…
what if there was a standard class like “Symb” or something, where you could say Symb(“some string literal”) and the resulting object would be hashable and would have Symb(“string a”) is Symb(“string a”) and they would only be == if the strings were equal, and such values would be immutable, and would not expose the string they come from except through __repr__ (which would return ‘Symb(“string a”)’ for example).
This way you wouldn’t need to import the class extending Enum, only the class Symb (or whatever it would be called), but, unlike with string literals, there would be no temptation to do string operations on it.
Hm, though, this doesn’t seem to facilitate a nice “does this case statement cover all the options of the enum” thing?
Though maybe you could like, take a set of such things as serving a similar role as an Enum class?
(Edit: this is in part inspired by lisp symbols)
for dynamic languages like python/js strings are fine. enums are really more powerful/necessary in compiled, statically-typed languages like java or c++
Plus, you can add string literals directly to type hints. But then you have the issue of propagating those parameters through to higher order calling functions. Maybe if you assigned a type alias to the collection of strings….
Wait, that’s just an enum again.
usually we address this by having a specific folder for enums
Seems more of a structural problem to me. Plus python allows you to import an import of your import, so this can also be pretty easy, if you are using a module that uses this enum.
And now I need to make a "Yo Dawg" meme.
First
Second
third
Fifth
0th
auto()
Would you speak in a plain way. Cause your accent is absolutely warning
Yeah sure, I'll just change the accent I've had my entire life to suit you.
@Carberra I know you are strong in what you are making about. But the your answer to the comment is absolutely tough
After rust, enums in other languages feel childish at best. Like what’s with myenum = 0. What does it even mean intuitively? C, go, … does it. And python has jumped onboard with something half-baked as usual. Pro-tip, like others have mentioned already, use dataclasses and your future self will thank you for it.
how do you use a dataclass in a situation where you'd usually use an enum?
6:26 you got "redgreen" because you called them in a print(). If you call them outside, you'll get