@@ -191,6 +191,11 @@ def __new__(metacls, cls, bases, classdict):
191
191
# Reverse value->name map for hashable values.
192
192
enum_class ._value2member_map_ = {}
193
193
194
+ # used to speedup __str__, __repr__ and __invert__ calls when applicable
195
+ enum_class ._repr_ = None
196
+ enum_class ._str_ = None
197
+ enum_class ._invert_ = None
198
+
194
199
# If a custom type is mixed into the Enum, and it does not know how
195
200
# to pickle itself, pickle.dumps will succeed but pickle.loads will
196
201
# fail. Rather than have the error show up later and possibly far
@@ -265,6 +270,15 @@ def __new__(metacls, cls, bases, classdict):
265
270
except TypeError :
266
271
pass
267
272
273
+ # after all members created, cache result of this
274
+ # methods for immutable values
275
+ for member in enum_class ._value2member_map_ .copy ().values ():
276
+ for static_attr in ('__repr__' , '__str__' , '__invert__' ):
277
+ method = getattr (member , static_attr , None )
278
+ if method is None :
279
+ continue
280
+ setattr (member , static_attr [1 :- 1 ], method ())
281
+
268
282
# double check that repr and friends are not the mixin's or various
269
283
# things break (such as pickle)
270
284
for name in {'__repr__' , '__str__' , '__format__' , '__reduce_ex__' }:
@@ -630,10 +644,16 @@ def _value_(self):
630
644
631
645
@_value_ .setter
632
646
def _value_ (self , value ):
647
+ self ._repr_ = self ._str_ = None
648
+ if '_invert_' in self .__dict__ :
649
+ self ._invert_ = None
633
650
object .__setattr__ (self , 'value' , value )
634
651
635
652
@_name_ .setter
636
653
def _name_ (self , name ):
654
+ self ._repr_ = self ._str_ = None
655
+ if '_invert_' in self .__dict__ :
656
+ self ._invert_ = None
637
657
object .__setattr__ (self , 'name' , name )
638
658
639
659
def _generate_next_value_ (name , start , count , last_values ):
@@ -768,18 +788,27 @@ def __repr__(self):
768
788
cls = self .__class__
769
789
if self .name is not None :
770
790
return f'<{ cls .__name__ } .{ self .name } : { self .value !r} >'
791
+ cached = self ._repr_
792
+ if cached is not None :
793
+ return cached
771
794
members , uncovered = _decompose (cls , self .value )
772
- return f"<{ cls .__name__ } .{ '|' .join ([str (m .name or m .value ) for m in members ])} : { self .value !r} >"
795
+ members = '|' .join ([str (m .name or m .value ) for m in members ])
796
+ self ._repr_ = result = f"<{ cls .__name__ } .{ members } : { self .value !r} >"
797
+ return result
773
798
774
799
def __str__ (self ):
775
800
cls = self .__class__
776
801
if self .name is not None :
777
802
return f'{ cls .__name__ } .{ self .name } '
803
+ cached = self ._str_
804
+ if cached is not None :
805
+ return cached
778
806
members , uncovered = _decompose (cls , self .value )
779
807
if len (members ) == 1 and members [0 ].name is None :
780
- return f'{ cls .__name__ } .{ members [0 ].value !r} '
808
+ self . _str_ = result = f'{ cls .__name__ } .{ members [0 ].value !r} '
781
809
else :
782
- return f"{ cls .__name__ } .{ '|' .join ([str (m .name or m .value ) for m in members ])} "
810
+ self ._str_ = result = f"{ cls .__name__ } .{ '|' .join ([str (m .name or m .value ) for m in members ])} "
811
+ return result
783
812
784
813
def __bool__ (self ):
785
814
return bool (self .value )
@@ -803,13 +832,18 @@ def __xor__(self, other):
803
832
return cls (self .value ^ other .value )
804
833
805
834
def __invert__ (self ):
835
+ cached = self ._invert_
836
+ if cached is not None :
837
+ return cached
806
838
cls = self .__class__
807
839
members , uncovered = _decompose (cls , self .value )
808
840
inverted = cls (0 )
809
841
for m in cls :
810
842
if m not in members and not (m .value & self .value ):
811
843
inverted = inverted | m
812
- return cls (inverted )
844
+ self ._invert_ = result = cls (inverted )
845
+ result ._invert_ = self
846
+ return result
813
847
814
848
815
849
class IntFlag (int , Flag ):
@@ -880,7 +914,10 @@ def __xor__(self, other):
880
914
__rxor__ = __xor__
881
915
882
916
def __invert__ (self ):
883
- result = self .__class__ (~ self .value )
917
+ cached = self ._invert_
918
+ if cached is not None :
919
+ return cached
920
+ self ._invert_ = result = self .__class__ (~ self .value )
884
921
return result
885
922
886
923
0 commit comments