Special method __cmp__ doesn't work - python

The special work __cmp__ doesn't work. Say the following code:
class Test():
def __cmp__(self, other):
return False
t1 = Test()
t2 = t1
print t2 == t1
I should get False because that the cmp is always returning False. But actually, python is printing True for me.
Any suggestion?

__cmp__ should return -1, 0 or 1, indicating of it's lower than, equal to or higher than other. Returning False will actually make it compare as equal to everything, as the integer value of False is 0.
class Test():
def __cmp__(self, other):
return -1
Also note that __cmp__ is deprecated and is ignored in Python 3. You should implement __eq__ and the other so called rich comparison operators instead.

Related

What is the difference between assertIs and assertTrue in unittest module, when these methods are applied on True values?

My working environment:
OS: Ubuntu 18.04 (64 bits)
Python version: 3.8.0 (64 bits)
I've a question about the unittest documentation, more precisely, the difference between assertTrue and assertIs methods. Here is what the online documentation says:
https://docs.python.org/3/library/unittest.html
assertTrue(expr, msg=None)
assertFalse(expr, msg=None)
Test that expr is true (or false).
Note that this is equivalent to bool(expr) is True and not to expr is
True (use assertIs(expr, True) for the latter).
I don't really understand the difference, that is, in the case where I have a boolean type with a True value, then why should I use assertIs instead of assertTrue? Given that bool(True) is True also returns the True boolean value I don't see the difference and impact on tests. I'd appreciate if you could kindly make some clarification.
To answer the question you have to understand the difference between is and == comparison operators, imagine you have two different boys, but they are both Peters, they have the same name so == will give you true, but is will give you False, because they are not one person.
import unittest
class MyClass:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
class TestStringMethods(unittest.TestCase):
def test_your_func(self):
x = MyClass(5)
y = MyClass(5)
z = x
print(x is y) # False x is not y, they are separate object
print(x == y) # True 5 == 5
print(x is z) # True, because z is the reference to the same object
print(z == y) # True 5 == 5
# self.assertIs(x, y) # if you uncomment the line you'll get error
self.assertIs(x, z)
if __name__ == '__main__':
unittest.main()
As per AssertTruem it has absolutely different purpose to use, e.g. if []: is False and if [1] is True.
You are basically right - in most cases in tests you will probably use assertTrue for the check instead of assertIs(True).
The only really useful case where you actually need assertIs(True) would be if you want to check that the checked expression actually returns a bool value, e.g.:
def test_bool(self):
a = True
b = 1
self.assertTrue(a)
self.assertIs(a, True)
self.assertTrue(b)
self.assertIsNot(b, True)
This could be interesting if you have a function that may return values of different types, and you want to ensure that it returns a concrete bool value. Consider a (nonsense) function:
def fct(param):
if param < 0:
return False
if param > 0:
return True
return 42
...
def test_fct(self):
assertTrue(fct(1)) # will not ensure that it returns True
assertTrue(fct(0)) # also passes
assertIs(True, fct(1)) # passes as intended
assertIs(True, fct(0)) # fails, as it should
It can also help to ensure that your tested function that is supposed to return a bool value actually does that (and not just some value that would evaluate to True or False, like None or a number, due to some bug).
This all works of course because (like None), True and False are singleton objects, e.g. there is always only one of each of them.

Is it possible for `__contains__` to return non-boolean value?

The documentation says that __contains__ should return true if item is in self, false otherwise. However, if the method returns a non-boolean value x, it seems that python automatically converts it to bool(x).
Is there any way to avoid that, and return the actual value x? Or is this feature behavior implemented directly in the interpreter and there's no way to change this?
Note that it's not __contains__ that converts the value to a Boolean, but the in operator that calls __contains__. With
class Foo(list):
def __contains__(self, v):
if super().__contains__(v):
return v
else:
return False
>>> f = Foo([1,2,3])
>>> f.__contains__(2)
2
>>> 2 in f
True
A foo in bar will be compiled to COMPARE_OP (in) for CPython3. The implementation uses PySequence_Contain() and then coerces to result to a bool. So while you could return something else, you always end up with a bool after the call.
__bool__ is indeed being called on the return value of __contains__.
Consider the following classes:
class BoolWithPrint:
def __init__(self, value):
self.value = value
def __bool__(self):
print("Im being booled.")
return self.value
class StrangeContains:
def __contains__(self, x):
return BoolWithPrint(x)
... which behave like this:
>>> True in StrangeContains()
Im being booled.
True
>>> False in StrangeContains()
Im being booled.
False
>>> 'stuff' in StrangeContains()
Im being booled.
[...]
TypeError: __bool__ should return bool, returned str
So as far as I know, you are out of luck. You could sneakily override __bool__ on the value __contains__ returns, but that will only delay the TypeError because __bool__ must return True or False.
For additional context, see Can the Python bool() function raise an exception for an invalid argument?.
In Python documentation, section 6.10.2. Membership test operations says:
For user-defined classes which define the __contains__() method, x in y
returns True if y.__contains__(x) returns a true value, and False
otherwise.
So clearly, if you return a non-bool, the in operator will still return a boolean.
If you directly call __contains__, then of course you will get whatever result is returned from it.
For example:
class X:
def __contains__(self, other):
return 11
x = X()
8 in x # True
x.__contains__(8) # 11

Why is `int.__eq__(other)` a working comparison?

The following code works with Python 2.7:
>>> class Derived(int):
... def __eq__(self, other):
... return int.__eq__(other)
...
>>> Derived(12) == 12.0
True
>>> Derived(12) == 13
False
I do not understand, why it works, given that the self attribute is not explicitly given to int.__eq__() method call.
[EDIT]
Answers so far suggested, that it is about returning NotImplemented by self.__eq__(other) and thus calling other.__eq__(self). Then Derived(12) == Derived(12) I expect to be an infinitive recursion, which is not the case:
>>> Derived(12) == Derived(12)
True
It works because int.__eq__(<something>) returns NotImplemented and when that happens it results in a call to other.__eq__(self) and that's what is returning True and False here.
Demo:
class Derived(int):
def __eq__(self, other):
print self, other
print int.__eq__(other)
print other.__eq__(self)
return int.__eq__(other)
>>> Derived(12) == 12.0
12 12.0
NotImplemented
True
True
>>> Derived(12) == 13.0
12 13.0
NotImplemented
False
False
From NotImplemented
's docs:
Special value which should be returned by the binary special methods
(e.g. __eq__(), __lt__(), __add__(), __rsub__(), etc.) to
indicate that the operation is not implemented with respect to the
other type; may be returned by the in-place binary special methods
(e.g. __imul__(), __iand__(), etc.) for the same purpose. Its
truth value is true.
Note When NotImplemented is returned, the interpreter will then try
the reflected operation on the other type, or some other fallback,
depending on the operator. If all attempted operations return
NotImplemented, the interpreter will raise an appropriate exception.
What happens when both __eq__ return NotImplemented?
The behaviour is different in Python 2 and 3.
In Python 2 it falls back to __cmp__ method first and integers have __cmp__ method in Python 2. It has been removed in Python 3.
As per Python 2 docs if nothing is found it ultimately falls back to identity comparison:
If no __cmp__(), __eq__() or __ne__() operation is defined, class
instances are compared by object identity (“address”)
class Derived(int):
def __eq__(self, other):
print ("Inside __eq__")
return NotImplemented
def __cmp__(self, other):
print ("Inside __cmp__ finally")
return True
>>> Derived(12) == Derived(12)
Inside __eq__
Inside __eq__
Inside __cmp__ finally
False
Not let's define a class with no method defined:
class Derived(object):
pass
>>> Derived() == Derived()
False
>>> d = Derived()
>>> d == d # Same objects.
True
Python 3 doesn't have __cmp__ method anymore but it seems to be falling back to identity now. And it seems it is not documented either.
# Python 3.5
>>> Derived() == Derived()
False
>>> d = Derived()
>>> d == d
True
When mixing float with an integer type, there's no good uniform approach.
https://github.com/python/cpython/blob/2.7/Objects/floatobject.c#L401-L417
P.S.
How int() object using "==" operator without __eq__() method in python2?
In Python 2.7, if you call int.__eq__ it always returns NotImplemented. Example:
>>> int.__eq__(12.0)
NotImplemented
When you use the == operator it will attempt to run the __eq__ method on the left argument, and if it gets NotImplemented it will return the result of the __eq__ method from the argument on the right.
In your example for Derived(12) == 12.0, the interpreter first tries Derived(12).__eq__(12.0), and gets NotImplemented. It then runs the __eq__ method on the float number 12.0 and gets True.
In the case of your Derived(12) == Derived(12) example, what's likely happening is that since both objects return NotImplemented for their __eq__ methods, and since Derived inherits from int, the interpreter falls back to using the cmp builtin behavior for int (according to this answer, which is linked-to in another answer to your question).
Here's an example that illustrates your case:
class Derived(int):
def __eq__(self, other):
print 'Doing eq'
return NotImplemented
def __cmp__(self, other):
print 'doing cmp'
return 0 # contrived example - don't do this
>>> Derived(12) == Derived(12)
doing eq
doing eq
doing cmp
True

overriding __cmp__ python function

Hi I am overriding __cmp__ . If the second object passed is None, or if it is not an instance of someClass, then it returns -1.
I don't understand what exactly is happening here.
class someClass():
def __cmp__(self, obj):
if obj == None:
return -1
if not isinstance(obj, someClass):
return -1
My test function:
def test_function(self):
obj1 = someClass()
self.assertTrue(obj1 < None)
# I get true.
self.assertTrue(obj1 > None)
# I get failure as False is returned.
Could anyone please explain to me:
What are the return values?
How is it deciding whether it will return True or False when the comparison signs are changed?
The convention for __cmp__ is:
a < b : return -1
a = b : return 0
a > b : return 1
This of course makes only sense if both a and b are of compatible types, say numbers. If you have a 'corner case', where a or b is either None or incompatible (not instanceof), you should report an error, as this is a programming error in the use of the comparison operators on your someClass instance.
It is possible to implement any behaviour with __cmp__, but a comparison with None the way described by the OP will eventually lead to strange behaviour and bugs.
see also: __lt__ instead of __cmp__
http://docs.python.org/reference/datamodel.html#object.__cmp__
When the obj is None, your program will return -1, while returning a negative integer means self < obj, so obj1 < None is True, and obj1 > None is false.
If you look at the python documentation, you'll see that the cmp function return -1 if self < other.
Since __cmp__(obj, None) == -1, it assumed that obj < None.
My guess if __cmp__(obj, None) should return 1 as any object is superior to no object :)

What am I doing wrong(implementing alternative equality with overloading in python)

A person asked a question on SO about how to get a list unique function in python with an alternative equality function.
I was thinking it could be done by inheriting from the element class and overloading the equality function
import functools
#functools.total_ordering
class ffloat(float):
def __eq__(self,other):
if floor(self) == floor(other):
return True
else:
return False
def __le__(self,other):
if self == other:
return True
else:
return float(self) <= float(other)
def __hash__(self):
return floor(self)
a = map(ffloat,[4.3,8,8.9, 13])
In [41]: a[1] == a[2]
Out[41]: True
but
In [42]: set(a)
Out[42]: set([4.3, 8.0, 8.9, 13.0])
Edit: replaced abs < 1.5 equality with floor equality
Added Hash
P.S. is there a way to make a class factory out of this that a class and two lambda and returns a class that inherits from the first one overriding the needed equality function.
This is not a valid equality function, since it's not transitive:
mfloat(0) == mfloat(1) == mfloat(2), but mfloat(0) != mfloat(2).
Also note that in order to be used in a set, you must override __hash__ so that the following property holds for all instances a, b of your class:
a == b ⇒ hash(a) == hash(b)
set finds out that hash(mfloat(8)) != hash(mfloat(9)). Since set assumes the above property holds, it concludes that mfloat(8) != mfloat(9) without actually calling __eq__.
In summary, this works:
from math import floor
class ffloat(float):
def __eq__(self,other):
return floor(self) == floor(other):
def __hash__(self):
return floor(self)
a = map(ffloat,[4.3,8,8.9, 13])
print(set(a))
# output: {8.0, 4.3, 13.0}

Categories

Resources