r/backtickbot • u/backtickbot • Jan 26 '21
https://np.reddit.com/r/Python/comments/l47ppr/why_we_dont_use_python_native_enums/gktp1uo/
I thought this article was trying a bit too hard to discount Python's Enum's. (Regardless of whether or not they're promoting their creation, tritokens.)
Wrt "no semantics": that's a bad example to show name vs value issues.
Fruit.apple = 'Apple'should have just beenFruit.Apple = auto() # or 1- which is exactly how it was done in the docs' test example. For enums, it's the members that have meaning/significance, not their values. The values indicate things like flags or ordering.In the vast majority of use-cases, one doesn’t care what the actual value of an enumeration is.
In any case, for storage in a DB - it's not ambiguous. Consider that the value could be a tuple, or a list, or a dict - which isn't going into a DB. It would have to be the Name (the member). Every time. (And normalised; where integer values in the DB need not be related to the value stored in the enum.)
Hard to add data? You mention "It’s impossible to understand the definition of the data without reading the constructor" - then just move the constructor definition to the top and the planets after. Python doesn't care.
If the clarity of the fields' names was a concern, could have used a
namedtuple. Less repetition in the definition ofPlanetsthan in the "tri.token" approach, and equally clear. (Too bad they didn't do it this way in the Python docs, but those were just examples illustrating potential.)Planet = namedtuple('Planet', 'mass radius') class Planets(Enum): MERCURY = Planet(3.303e+23, 2.4397e6) VENUS = Planet(4.869e+24, 6.0518e6) EARTH = Planet(5.976e+24, 6.37814e6) MARS = Planet(6.421e+23, 3.3972e6) ...Also, for "and the constructor is a bit weird too as self here are the cases, not the Planet class!" - the docs clearly state that enum classes are not normal classes. Just like metaclasses and dataclasses are not normal classes. The same could be said of namedtuples, because you can't simply inherit from one and add a member (attribute).
Even though we use the
classsyntax to create Enums, Enums are not normal Python classes. See How are Enums different? for more details.Wrt "scales badly for sparse data" - if you have that many items per Field, again, could have just used a namedtuple with defaults.
default = object() Field = namedtuple('Field', 'a b c d e dw_name g h i j', defaults=(default, None, None, None, None, None, default, None, None, None)) class Fields(Enum): party_group_name = Field(dw_name='rec_party') another_field = Field(a='no', b='other', c='columns') ...And I want to be clear: The issue in the blog's example was not 'sparse fields'. It had nothing to do with enums. It's to do with what's on the right-hand-side of the
=sign - what data structure you're using to store those values (not members). Could have just been simple class instances. And more recently, dataclasses.Members of enums with the same value are considered aliases, with the first definition being the primary. The code in #4 should not have been an enum in the first place. And imho, not allowing aliases in enums (the
@uniquedecorator) should have been the default.
My view: Python's enum's are good, but not necessarily great. But...some 'enum' examples in the blog should have been dataclasses, or just plain classes/containers.
As mentioned "tritoken" was created before enum's existed and have a bunch of extra features - which would occur when you roll your own solution. And invariably it has specific features and use-cases you need but are not universally applicable.