@@ -44,7 +44,7 @@ def _superhash(value):
4444def EqHash (* names ,
4545 ** kwargs ):
4646 """
47- EqHash(*names, include_super=False, superhash=False, include_type=False)
47+ EqHash(*names, include_super=False, superhash=False, supereq=False, include_type=False)
4848
4949 A class decorator factory for the common pattern of writing
5050 ``__eq__``/``__ne__`` and ``__hash__`` methods that check the same
@@ -70,24 +70,43 @@ def EqHash(*names,
7070 >>> hash(ChildThing()) != hash(Thing()) != 0
7171 True
7272
73+
74+ >>> @EqHash('d', supereq=True)
75+ ... class Thing2:
76+ ... def __init__(self, d): self.d = d
77+ >>> Thing2([]) == Thing2(())
78+ True
79+ >>> Thing2(set()) == Thing2(frozenset())
80+ True
81+
82+
7383 :keyword include_super: If set to ``True`` (*not* the default)
7484 then the equality (and perhaps hash) values of super will be considered.
7585 :keyword superhash: If set to ``True`` (*not* the default),
7686 then the hash function will be made to support certain
7787 mutable types (lists and dictionaries) that ordinarily cannot
7888 be hashed. Use this only when those items are functionally
7989 treated as immutable.
90+ :keyword bool supereq: If set to ``True`` (*not* the default),
91+ then the equality method will treat lists and tuples as being
92+ equal. This is useful, for example, when you have a class
93+ default that's an immutable tuple, but instances might
94+ have their own list value (containing the same data)
8095 :keyword include_type: If set to ``True`` (*not* the default),
8196 equality will only be true if the other object is an instance
8297 of the class this is declared on. Use this only when there are
8398 a series of subclasses who differ in no attributes but should not
8499 compare equal to each other. Note that this can lead to violating
85100 the commutative property.
86101
102+ .. versionchanged:: NEXT
103+ Make *superhash* apply to the equality operator as well for
104+ comparing mutable and immutable objects.
87105 """
88106
89107 _include_super = kwargs .pop ('include_super' , False )
90108 superhash = kwargs .pop ("superhash" , False )
109+ supereq = kwargs .pop ('supereq' , False )
91110 _include_type = kwargs .pop ('include_type' , False )
92111
93112 if kwargs :
@@ -98,14 +117,15 @@ def EqHash(*names,
98117
99118 def x (cls ):
100119 __eq__ , __hash__ , __ne__ = _eq_hash (cls , names ,
101- _include_super , _include_type , superhash )
120+ _include_super , _include_type , superhash ,
121+ supereq )
102122 cls .__eq__ = __eq__
103123 cls .__hash__ = __hash__
104124 cls .__ne__ = __ne__
105125 return cls
106126 return x
107127
108- def _make_eq (cls , names , include_super , include_type ): # pylint:disable=unused-argument
128+ def _make_eq (cls , names , include_super , include_type , supereq ): # pylint:disable=unused-argument
109129 # 1 and 0 are constants and faster to load than the globals True/False
110130 # (in python 2)
111131
@@ -131,25 +151,38 @@ def _make_eq(cls, names, include_super, include_type): # pylint:disable=unused-a
131151 eq_stmt += ' a = self.' + name + '\n '
132152 eq_stmt += ' try:\n b = other.' + name + '\n '
133153 eq_stmt += ' except AttributeError: return NotImplemented\n '
134- eq_stmt += ' if a != b: return 0\n \n '
135-
136- eq_stmt += ' return 1'
154+ if supereq :
155+ # pylint:disable-next=line-too-long
156+ eq_stmt += ' if a != b and type(a) != type(b):\n '
157+ # We use isinstance rather than exact ``type(a) in (list, tuple)`` to work for
158+ # subclasses of the standard library classes, like named tuples. However, the
159+ # consequence is that if the user-subclass defined special behaviour, we lose
160+ # it. That's why we check a!=b FIRST so if there was custom behaviour that
161+ # made it pass, it still gets called. The cost is calling the __ne__ method twice.
162+ eq_stmt += ' if isinstance(a, (list, tuple)) and isinstance(b, (list,tuple)):\n '
163+ eq_stmt += ' a = tuple(a); b = tuple(b)\n '
164+ # sets and frozensets compare correctly automatically.
165+ eq_stmt += ' else: return False\n '
166+ eq_stmt += ' if a != b: return False\n \n '
167+
168+ eq_stmt += ' return True'
137169
138170 # Must use a custom dictionary under Py3
139171 lcls = dict (locals ())
140172 exec (eq_stmt , globals (), lcls ) # pylint:disable=exec-used
141173
142174 return lcls ['__eq__' ]
143175
144- def _eq_hash (cls , names , include_super , include_type , superhash ):
145- # pylint:disable=too-complex
176+ def _eq_hash (cls , names , include_super , include_type ,
177+ superhash = False , supereq = False ):
178+ # pylint:disable=too-complex,too-many-locals,too-many-positional-arguments
146179 names = tuple ((str (x ) for x in names )) # make sure they're native strings, not unicode on Py2
147180 # We assume the class hierarchy of these objects does not change
148181 if include_super :
149182 superclass = cls .__mro__ [1 ]
150183 superclass_hash = superclass .__hash__
151184
152- __eq__ = _make_eq (cls , names , include_super , include_type )
185+ __eq__ = _make_eq (cls , names , include_super , include_type , supereq )
153186
154187 def __ne__ (self , other ):
155188 eq = __eq__ (self , other )
0 commit comments