Skip to content

Commit 65c4316

Browse files
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 ed136b9) Co-authored-by: Michael Droettboom <[email protected]>
1 parent 421c4b0 commit 65c4316

File tree

3 files changed

+13
-8
lines changed

3 files changed

+13
-8
lines changed

Lib/enum.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,16 +309,17 @@ def __set_name__(self, enum_class, member_name):
309309
if descriptor and not need_override:
310310
# previous enum.property found, no further action needed
311311
pass
312-
else:
312+
elif descriptor and need_override:
313313
redirect = property()
314314
redirect.__set_name__(enum_class, member_name)
315-
if descriptor and need_override:
316-
# previous enum.property found, but some other inherited attribute
317-
# is in the way; copy fget, fset, fdel to this one
318-
redirect.fget = descriptor.fget
319-
redirect.fset = descriptor.fset
320-
redirect.fdel = descriptor.fdel
315+
# Previous enum.property found, but some other inherited attribute
316+
# is in the way; copy fget, fset, fdel to this one.
317+
redirect.fget = descriptor.fget
318+
redirect.fset = descriptor.fset
319+
redirect.fdel = descriptor.fdel
321320
setattr(enum_class, member_name, redirect)
321+
else:
322+
setattr(enum_class, member_name, enum_member)
322323
# now add to _member_map_ (even aliases)
323324
enum_class._member_map_[member_name] = enum_member
324325
try:
@@ -647,7 +648,7 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
647648
'member order does not match _order_:\n %r\n %r'
648649
% (enum_class._member_names_, _order_)
649650
)
650-
#
651+
651652
return enum_class
652653

653654
def __bool__(cls):

Lib/test/test_enum.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,6 +2611,7 @@ class Private(Enum):
26112611
self.assertEqual(Private._Private__corporal, 'Radar')
26122612
self.assertEqual(Private._Private__major_, 'Hoolihan')
26132613

2614+
@unittest.skip("Accessing all values retained for performance reasons, see GH-93910")
26142615
def test_exception_for_member_from_member_access(self):
26152616
with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
26162617
class Di(Enum):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The ability to access the other values of an enum on an enum (e.g.
2+
``Color.RED.BLUE``) has been restored in order to fix a performance
3+
regression.

0 commit comments

Comments
 (0)