[Python-checkins] gh-93910: Fix enum performance regression (GH-94614)

miss-islington webhook-mailer at python.org
Thu Jul 7 08:01:48 EDT 2022


https://github.com/python/cpython/commit/65c431685b40583b877da573e41514d63217815d
commit: 65c431685b40583b877da573e41514d63217815d
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-07-07T05:01:09-07:00
summary:

gh-93910: Fix enum performance regression (GH-94614)


This removes the performance regression in 3.11, **at the expense of not fixing
the "bug" that allows accessing values from values** (e.g. `Color.RED.BLUE`).

Using the benchmark @markshannon [presented](https://github.com/python/cpython/issues/93910GH-issuecomment-1165503032), the results are:

| Version | Enum | Fast enum | Normal class |
| --- | --- | --- | --- |
| 3.10 | 2.04 | 0.59 | 0.56 |
| 3.11 | 2.78 | 0.31 | 0.15 |
| This PR | 1.30 | 0.32 | 0.16 |

I share this mostly as information about the source of the regression, as this may be useful. It may be that the lower-risk approach for the beta is just to revert to a previously-known working state.
(cherry picked from commit ed136b96737fdbeff864079d12904cb962c6cce5)

Co-authored-by: Michael Droettboom <mdboom at gmail.com>

files:
A Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst
M Lib/enum.py
M Lib/test/test_enum.py

diff --git a/Lib/enum.py b/Lib/enum.py
index e11093c6cf468..e5971917cef46 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -309,16 +309,17 @@ def __set_name__(self, enum_class, member_name):
         if descriptor and not need_override:
             # previous enum.property found, no further action needed
             pass
-        else:
+        elif descriptor and need_override:
             redirect = property()
             redirect.__set_name__(enum_class, member_name)
-            if descriptor and need_override:
-                # previous enum.property found, but some other inherited attribute
-                # is in the way; copy fget, fset, fdel to this one
-                redirect.fget = descriptor.fget
-                redirect.fset = descriptor.fset
-                redirect.fdel = descriptor.fdel
+            # Previous enum.property found, but some other inherited attribute
+            # is in the way; copy fget, fset, fdel to this one.
+            redirect.fget = descriptor.fget
+            redirect.fset = descriptor.fset
+            redirect.fdel = descriptor.fdel
             setattr(enum_class, member_name, redirect)
+        else:
+            setattr(enum_class, member_name, enum_member)
         # now add to _member_map_ (even aliases)
         enum_class._member_map_[member_name] = enum_member
         try:
@@ -647,7 +648,7 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
                         'member order does not match _order_:\n  %r\n  %r'
                         % (enum_class._member_names_, _order_)
                         )
-        #
+
         return enum_class
 
     def __bool__(cls):
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index ac5c52b2b303b..f9a662746fb1a 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -2611,6 +2611,7 @@ class Private(Enum):
         self.assertEqual(Private._Private__corporal, 'Radar')
         self.assertEqual(Private._Private__major_, 'Hoolihan')
 
+    @unittest.skip("Accessing all values retained for performance reasons, see GH-93910")
     def test_exception_for_member_from_member_access(self):
         with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
             class Di(Enum):
diff --git a/Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst b/Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst
new file mode 100644
index 0000000000000..2e589118e3efd
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-06-14-45-12.gh-issue-93910.iZcp67.rst
@@ -0,0 +1,3 @@
+The ability to access the other values of an enum on an enum (e.g.
+``Color.RED.BLUE``) has been restored in order to fix a performance
+regression.



More information about the Python-checkins mailing list