From d721bbd6664d65b8308b9ebed1251539ae02d093 Mon Sep 17 00:00:00 2001 From: Carl Friedrich Bolz-Tereick Date: Tue, 12 Oct 2021 20:30:25 +0200 Subject: [PATCH 1/3] bpo-45417: fix quadratic behaviour in the enum module creating an enum class used to be quadratic in the number of fields, in two different places: in the dicitonary implementation for the enum class, and when setting the name of all members. fix the former by switching to a dictionary instead of a list to store the fields while building up the dictionary. fix the latter by trying to use the already existing dictionary when looking up a field, instead of looping of all fields. --- Lib/enum.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Lib/enum.py b/Lib/enum.py index 0776761ae6e735..cfdee3a69c765c 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -235,11 +235,18 @@ def __set_name__(self, enum_class, member_name): enum_member._sort_order_ = len(enum_class._member_names_) # If another member with the same value was already defined, the # new member becomes an alias to the existing one. - for name, canonical_member in enum_class._member_map_.items(): - if canonical_member._value_ == enum_member._value_: - enum_member = canonical_member - break - else: + try: + try: + # try to do a fast lookup to avoid the quadratip loop + enum_member = enum_class._value2member_map_[value] + except TypeError: + for name, canonical_member in enum_class._member_map_.items(): + if canonical_member._value_ == value: + enum_member = canonical_member + break + else: + raise KeyError + except KeyError: # this could still be an alias if the value is multi-bit and the # class is a flag class if ( @@ -301,7 +308,7 @@ class _EnumDict(dict): """ def __init__(self): super().__init__() - self._member_names = [] + self._member_names = {} # use a dict to keep insertion order self._last_values = [] self._ignore = [] self._auto_called = False @@ -365,7 +372,7 @@ def __setitem__(self, key, value): ) self._auto_called = True value = value.value - self._member_names.append(key) + self._member_names[key] = None self._last_values.append(value) super().__setitem__(key, value) From 98aae2d91a684dfa73e1fcb9dfa850577ddca964 Mon Sep 17 00:00:00 2001 From: Carl Friedrich Bolz-Tereick Date: Tue, 12 Oct 2021 20:35:10 +0200 Subject: [PATCH 2/3] add news --- .../next/Library/2021-10-12-20-35-06.bpo-45417.gQM-O7.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2021-10-12-20-35-06.bpo-45417.gQM-O7.rst diff --git a/Misc/NEWS.d/next/Library/2021-10-12-20-35-06.bpo-45417.gQM-O7.rst b/Misc/NEWS.d/next/Library/2021-10-12-20-35-06.bpo-45417.gQM-O7.rst new file mode 100644 index 00000000000000..a15c23917a7e62 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-10-12-20-35-06.bpo-45417.gQM-O7.rst @@ -0,0 +1,2 @@ +Fix quadratic behaviour in the enum module: Creation of enum classes with a +lot of entries was quadratic. From f5771be20f49a4b2d70c001ac34526fed78b88f4 Mon Sep 17 00:00:00 2001 From: Carl Friedrich Bolz-Tereick Date: Tue, 12 Oct 2021 22:24:47 +0200 Subject: [PATCH 3/3] fix typo --- Lib/enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/enum.py b/Lib/enum.py index cfdee3a69c765c..461d276eed862a 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -237,7 +237,7 @@ def __set_name__(self, enum_class, member_name): # new member becomes an alias to the existing one. try: try: - # try to do a fast lookup to avoid the quadratip loop + # try to do a fast lookup to avoid the quadratic loop enum_member = enum_class._value2member_map_[value] except TypeError: for name, canonical_member in enum_class._member_map_.items():