I have a class MyClass where __eq__
is defined as follows:
def __eq__(self, other):
try:
other = MyClass(other)
except Exception as e:
raise ValueError(f"MyClass.__eq__ failed: {other} doesn't appear to be a valid MyClass type. \n", e )
prefix_i1 = re.findall("[ab]" , self )
prefix_i2 = re.findall("[ab]" , other )
if len( set( prefix_i1 prefix_i2 ) ) > 1:
return False # ie: "a07" != "b07" BUT "k07" == "b07"
else:
return self.num_string == other.num_string # eg: "i3" == "i03"
where
self.num_string = "".join(filter(str.isdigit, self )).zfill(2)
Unexpectedly, I get this result:
> MyClass('b05') == MyClass('i05')
True
> MyClass('b05') != MyClass('i05')
True
I thought __ne__
was by default not __eq__
and defining it explicitly was discouraged since Python 3.
What am I doing wrong?
Here is a minimal reproducible example:
import re
class MyClass(str):
def __new__(cls, *args, **kwargs):
if args[0] is None:
return str.__new__(cls, '' )
if not ( isinstance(args[0], int) or
( isinstance(args[0], str) and re.match("[iab]?[0-9]{1,2}", args[0].lower()) ) ):
raise ValueError("MyClass failed because the provided input '{}' is not valid... .".format(args[0]))
lower_str_input = str(args[0]).lower()
return str.__new__(cls, lower_str_input )
def __init__(self, input_string=''):
self.num_string = "".join(filter(str.isdigit, self )).zfill(2)
def __eq__(self, other):
try:
other = MyClass(other)
except Exception as e:
raise ValueError("MyClass.__eq__ failed" )
prefix_i1 = re.findall("[ab]" , self )
prefix_i2 = re.findall("[ab]" , other )
if len( set( prefix_i1 prefix_i2 ) ) > 1:
return False # ie: "a07" != "b07" BUT "k07" == "b07"
else:
return self.num_string == other.num_string # eg: "i3" == "i03"
MyClass('b05') == MyClass('i05')
MyClass('b05') != MyClass('i05')
CodePudding user response:
I thought
__ne__
was by defaultnot __eq__
and defining it explicitly was discouraged since Python 3.
For your own classes, yes. They will derive from object
by default, which implements that logic.
However, built-ins (and thus everything derived from them) can be a bit strange.
Here is a simpler example:
... class x(str):
... def __eq__(self, other):
... print('eq called')
... return str.__eq__(self, other)
...
>>> x('foo') != 'foo'
False
The answer is correct, but __eq__
is not called (thus there is no message printed). This answer comes from str.__ne__
, which (apparently) is separately implemented (not in terms of __eq__
).