Skip to content

Commit b2af211

Browse files
authored
bpo-45417: [Enum] fix quadratic behavior during creation (GH-28907)
Creating an Enum exhibited quadratic behavior based on the number of members in three places: - `EnumDict._member_names`: a list searched with each new member's name - member creation: a `for` loop checking each existing member to see if new member was a duplicate - `auto()` values: a list of all previous values in enum was copied before being sent to `_generate_next_value()` Two of those issues have been resolved: - `_EnumDict._member_names` is now a dictionary so lookups are fast - member creation tries a fast value lookup before falling back to the slower `for` loop lookup The third issue still remains, as `_generate_next_value_()` can be user-overridden and could corrupt the last values list if it were not copied.
1 parent 0bbea07 commit b2af211

File tree

2 files changed

+16
-7
lines changed

2 files changed

+16
-7
lines changed

Lib/enum.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,18 @@ def __set_name__(self, enum_class, member_name):
235235
enum_member._sort_order_ = len(enum_class._member_names_)
236236
# If another member with the same value was already defined, the
237237
# new member becomes an alias to the existing one.
238-
for name, canonical_member in enum_class._member_map_.items():
239-
if canonical_member._value_ == enum_member._value_:
240-
enum_member = canonical_member
241-
break
242-
else:
238+
try:
239+
try:
240+
# try to do a fast lookup to avoid the quadratic loop
241+
enum_member = enum_class._value2member_map_[value]
242+
except TypeError:
243+
for name, canonical_member in enum_class._member_map_.items():
244+
if canonical_member._value_ == value:
245+
enum_member = canonical_member
246+
break
247+
else:
248+
raise KeyError
249+
except KeyError:
243250
# this could still be an alias if the value is multi-bit and the
244251
# class is a flag class
245252
if (
@@ -301,7 +308,7 @@ class _EnumDict(dict):
301308
"""
302309
def __init__(self):
303310
super().__init__()
304-
self._member_names = []
311+
self._member_names = {} # use a dict to keep insertion order
305312
self._last_values = []
306313
self._ignore = []
307314
self._auto_called = False
@@ -365,7 +372,7 @@ def __setitem__(self, key, value):
365372
)
366373
self._auto_called = True
367374
value = value.value
368-
self._member_names.append(key)
375+
self._member_names[key] = None
369376
self._last_values.append(value)
370377
super().__setitem__(key, value)
371378

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix quadratic behaviour in the enum module: Creation of enum classes with a
2+
lot of entries was quadratic.

0 commit comments

Comments
 (0)