I just noticed a very weird behavior of Enum+defaultdict in pyhton. I define an enum like this, which collects some default dictionaries:
from enum import Enum
from collections import defaultdict
class A(Enum):
a = defaultdict(lambda: 1)
b = defaultdict(lambda: 2)
Then, when I look at what's inside A:
In [11]: A.a
Out[11]: <A.a: defaultdict(<function A.<lambda> at 0x7f773f03b510>, {})>
In [12]: A.b
Out[12]: <A.a: defaultdict(<function A.<lambda> at 0x7f773f03b510>, {})>
So A.b
is just an alias to A.a
. This looks a lot like a bug to me, even if there probably is some good reason behind. Any idea?
Addendum
Since it popped up in the comments, a note on why one would like to put a dict in an Enum. I find that it is very often useful to group constants into namespaces, so that one may access values as A.a.constant1
, A.b.constant1
, etc. At the moment, trying to do so with Enums raises an AttributeError
. Of course, one could do something like:
class A:
class a(Enum):
constant1 = 1
class b(Enum):
constant1 = 2
However, this does not leverage on the capabilities of Enum (iteration, access via __getitem__
etc).
If you give two enum members equal values, enum
will produce one enum member with two aliases rather than two distinct members.
Defaultdicts inherit equality comparison from dict
. That means the default factory isn't part of ==
comparisons. Your enum members have equal values, so they get merged.
Using mutable objects as enum values is usually a bad idea. They tend to break enum
design assumptions like "value equality doesn't change". Consider attaching these defaultdicts to your enum members in some other way.