@@ -585,14 +585,24 @@ def _set_new_attribute(cls, name, value):
585
585
return False
586
586
587
587
588
+
588
589
# Decide if/how we're going to create a hash function. Key is
589
590
# (unsafe_hash, eq, frozen, does-hash-exist). Value is the action to
590
- # take.
591
- # Actions:
592
- # '': Do nothing.
593
- # 'none': Set __hash__ to None.
594
- # 'add': Always add a generated __hash__function.
595
- # 'exception': Raise an exception.
591
+ # take. The common case is to do nothing, so instead of providing a
592
+ # function that is a no-op, use None to signify that.
593
+
594
+ def _hash_set_none (cls , fields ):
595
+ return None
596
+
597
+ def _hash_add (cls , fields ):
598
+ flds = [f for f in fields if (f .compare if f .hash is None else f .hash )]
599
+ return _hash_fn (flds )
600
+
601
+ def _hash_exception (cls , fields ):
602
+ # Raise an exception.
603
+ raise TypeError (f'Cannot overwrite attribute __hash__ '
604
+ f'in class { cls .__name__ } ' )
605
+
596
606
#
597
607
# +-------------------------------------- unsafe_hash?
598
608
# | +------------------------------- eq?
@@ -602,22 +612,22 @@ def _set_new_attribute(cls, name, value):
602
612
# | | | | +------- action
603
613
# | | | | |
604
614
# v v v v v
605
- _hash_action = {(False , False , False , False ): ( '' ) ,
606
- (False , False , False , True ): ( '' ) ,
607
- (False , False , True , False ): ( '' ) ,
608
- (False , False , True , True ): ( '' ) ,
609
- (False , True , False , False ): ( 'none' ) ,
610
- (False , True , False , True ): ( '' ) ,
611
- (False , True , True , False ): ( 'add' ) ,
612
- (False , True , True , True ): ( '' ) ,
613
- (True , False , False , False ): ( 'add' ) ,
614
- (True , False , False , True ): ( 'exception' ) ,
615
- (True , False , True , False ): ( 'add' ) ,
616
- (True , False , True , True ): ( 'exception' ) ,
617
- (True , True , False , False ): ( 'add' ) ,
618
- (True , True , False , True ): ( 'exception' ) ,
619
- (True , True , True , False ): ( 'add' ) ,
620
- (True , True , True , True ): ( 'exception' ) ,
615
+ _hash_action = {(False , False , False , False ): None ,
616
+ (False , False , False , True ): None ,
617
+ (False , False , True , False ): None ,
618
+ (False , False , True , True ): None ,
619
+ (False , True , False , False ): _hash_set_none ,
620
+ (False , True , False , True ): None ,
621
+ (False , True , True , False ): _hash_add ,
622
+ (False , True , True , True ): None ,
623
+ (True , False , False , False ): _hash_add ,
624
+ (True , False , False , True ): _hash_exception ,
625
+ (True , False , True , False ): _hash_add ,
626
+ (True , False , True , True ): _hash_exception ,
627
+ (True , True , False , False ): _hash_add ,
628
+ (True , True , False , True ): _hash_exception ,
629
+ (True , True , True , False ): _hash_add ,
630
+ (True , True , True , True ): _hash_exception ,
621
631
}
622
632
# See https://bugs.python.org/issue32929#msg312829 for an if-statement
623
633
# version of this table.
@@ -774,7 +784,6 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
774
784
'functools.total_ordering' )
775
785
776
786
if frozen :
777
- # XXX: Which fields are frozen? InitVar? ClassVar? hashed-only?
778
787
for fn in _frozen_get_del_attr (cls , field_list ):
779
788
if _set_new_attribute (cls , fn .__name__ , fn ):
780
789
raise TypeError (f'Cannot overwrite attribute { fn .__name__ } '
@@ -785,23 +794,10 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen):
785
794
bool (eq ),
786
795
bool (frozen ),
787
796
has_explicit_hash ]
788
-
789
- # No need to call _set_new_attribute here, since we already know if
790
- # we're overwriting a __hash__ or not.
791
- if hash_action == '' :
792
- # Do nothing.
793
- pass
794
- elif hash_action == 'none' :
795
- cls .__hash__ = None
796
- elif hash_action == 'add' :
797
- flds = [f for f in field_list if (f .compare if f .hash is None else f .hash )]
798
- cls .__hash__ = _hash_fn (flds )
799
- elif hash_action == 'exception' :
800
- # Raise an exception.
801
- raise TypeError (f'Cannot overwrite attribute __hash__ '
802
- f'in class { cls .__name__ } ' )
803
- else :
804
- assert False , f"can't get here: { hash_action } "
797
+ if hash_action :
798
+ # No need to call _set_new_attribute here, since by the time
799
+ # we're here the overwriting is unconditional.
800
+ cls .__hash__ = hash_action (cls , field_list )
805
801
806
802
if not getattr (cls , '__doc__' ):
807
803
# Create a class doc-string.
0 commit comments