Difference between 'not x' and 'x==None' in python - python

Can not x and x==None give different answers if x is a class instance ?
I mean how is not x evaluated if x is a class instance ?

yes it can give different answers.
x == None
will call the __eq__() method to valuate the operator and give the result implemented compared to the None singleton.
not x
will call the __nonzero__() (__bool__() in python3) method to valuate the operator. The interpreter will convert x to a boolean (bool(x)) using the mentioned method and then inverse its returned value because of the not operator.
x is None
means that the reference x points to the None object, which is a singleton of type NoneType and will valuate false in comparaisons. The is operator tests object identity, and thus whether or not the two objects compared are the same instance of an object, and not similar objects.

class A():
def __eq__(self, other): #other receives the value None
print 'inside eq'
return True
def __nonzero__(self):
print 'inside nonzero'
return True
...
>>> x = A()
>>> x == None #calls __eq__
inside eq
True
>>> not x #calls __nonzero__
inside nonzero
False
not x is eqivalent to:
not bool(x)
Py 3.x:
>>> class A(object):
def __eq__(self, other): #other receives the value None
print ('inside eq')
return True
def __bool__(self):
print ('inside bool')
return True
...
>>> x = A()
>>> x == None #calls __eq__
inside eq
True
>>> not x #calls __bool__
inside bool
False

Yes; not uses __bool__ (in Python 3; Python 2 uses __nonzero__), and x == None can be overridden by __eq__.
(Both are shown here.)

If x is positive the not of it means negative and vice-versa.
x == None means it will only be True if x is None is True else False. Check this.
By positive I mean the if block is chosen. True is also positive.

not x is true for a wide variety of values, e.g. 0, None, "", False, [], {}, etc.
x == None is only true for the one specific value None.
If x is a class instance, then both not x and x == None will be false, but that doesn't mean that those are equivalent expressions.
Fine; that previous paragraph should read:
If x is a class instance, then both not x and x == None will be false unless someone is playing silly buggers with the class definition.

Related

Python, "print" and "return" resulted in different boolean logic

I recently started learning python through Sololearn and got to Recursion. To get better understanding of the code, I simplified it to:
def is_even(x):
return x
def is_odd(x):
return not is_even(x)
print(is_odd(2))
The return not is_even(x) is boolean and will resulted it as False and when it passed to the def is_even(x): it still would return as False.
However, when I change the return x to print(x)
def is_even(x):
print (x)
def is_odd(x):
return not is_even(x)
print(is_odd(2))
The result would be:
2
True
How did this happen? What is going on between the return not is_even(x) and print (x).
Thank you
Maybe this will get you on track:
def returning(x):
return x
def printing(x):
print(x)
returning(2)
# 2
printing(2)
# 2
a = returning(2)
a
# 2
b = printing(2)
2
b
# None
The difference is that return returns a value from a function which can be used to pass to another function / variable. print just prints out the information but does not return any value, this is why b holds no value, but during the assigment b = printing(2) it immediately printed out what was passed to it, when a = returning(2) did not, it assigned the value to variable a.
And None is falsly in python.
None == False
# False
None == True
# False
not None == True
# True
What you are lacking is for is_even to return a bool instead of the argument passed:
def is_even(x):
return x % 2 == 0
def is_odd(x):
return not is_even(x)
is_odd(3)
# True
Your code does not have any recursion!
the function is_even() returns anything you pass to it like an integer,a character or anything else.
the function is_odd() returns a boolean;But notice the equivalent boolean value for non boolean values.
For example values like 1, 'Example', [1,2,3] and ... have True boolean value and values like 0,[], None and ... have False boolean value.
So if you pass something like "test" or 5 to is_odd(), it will return False

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.

Do the commands "x is None" and "x == None" return always the same result if x is immutable? [duplicate]

This question already has answers here:
Python None comparison: should I use "is" or ==?
(6 answers)
Closed 2 years ago.
If the Python name x in Python refers to an immutable value, would these two statements return the same result and do an equivalent / identical check?
x is None vs x == None
I couldn't find an exact duplicate of this question, but perhaps it's still answered implicitly elsewhere, but here are some related questions:
Python: if not val, vs if val is None
Why does `None is None is None` return True?
It has nothing to do with the immutability of x. None is a singleton for which is and == return identical results, unless the type of x defines a weird __eq__ method. The name x is either bound or not bound to the same object as None. If not, the identity check will always be False, regardless of what other type it is. The result of the equality check is up to the type of x, but will be the same as the identity check for most sane classes.
Now the caveat is that while you can't override is, since that's an identity check done by the interpreter, you can override ==. Aside from speed and consistency, here's a toy example showing why x is None is preferable to x == None:
class Test:
def __eq__(self, other):
if other is None:
return True
return self is other
>>> Test() == None
True
>>> None == Test()
True
>>> Test() is None
False
>>> None is Test()
False
The reason that both Test () == None and None == Test() return the same result has to do with how comparisons are evaluated, and the fact that None does not define an explicit __eq__ method. Normally, the interpreter calls type(left).__eq__(left, right) on the operands. If the left operand's type does not define __eq__ or the method returns NotImplemented, it attempts type(right).__eq__(right, left). Only if both fail does it fail over to a built-in identity check. Since None doesn't define an equality check, it will always use the check defined by the other object before failing over to the identity check.

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

Is there any difference between "foo is None" and "foo == None"?

Is there any difference between:
if foo is None: pass
and
if foo == None: pass
The convention that I've seen in most Python code (and the code I myself write) is the former, but I recently came across code which uses the latter. None is an instance (and the only instance, IIRC) of NoneType, so it shouldn't matter, right? Are there any circumstances in which it might?
is always returns True if it compares the same object instance
Whereas == is ultimately determined by the __eq__() method
i.e.
>>> class Foo(object):
def __eq__(self, other):
return True
>>> f = Foo()
>>> f == None
True
>>> f is None
False
You may want to read this object identity and equivalence.
The statement 'is' is used for object identity, it checks if objects refer to the same instance (same address in memory).
And the '==' statement refers to equality (same value).
A word of caution:
if foo:
# do something
Is not exactly the same as:
if x is not None:
# do something
The former is a boolean value test and can evaluate to false in different contexts. There are a number of things that represent false in a boolean value tests for example empty containers, boolean values. None also evaluates to false in this situation but other things do too.
(ob1 is ob2) equal to (id(ob1) == id(ob2))
The reason foo is None is the preferred way is that you might be handling an object that defines its own __eq__, and that defines the object to be equal to None. So, always use foo is None if you need to see if it is infact None.
There is no difference because objects which are identical will of course be equal. However, PEP 8 clearly states you should use is:
Comparisons to singletons like None should always be done with is or is not, never the equality operators.
is tests for identity, not equality. For your statement foo is none, Python simply compares the memory address of objects. It means you are asking the question "Do I have two names for the same object?"
== on the other hand tests for equality as determined by the __eq__() method. It doesn't cares about identity.
In [102]: x, y, z = 2, 2, 2.0
In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)
In [104]: x is y
Out[104]: True
In [105]: x == y
Out[105]: True
In [106]: x is z
Out[106]: False
In [107]: x == z
Out[107]: True
None is a singleton operator. So None is None is always true.
In [101]: None is None
Out[101]: True
For None there shouldn't be a difference between equality (==) and identity (is). The NoneType probably returns identity for equality. Since None is the only instance you can make of NoneType (I think this is true), the two operations are the same. In the case of other types this is not always the case. For example:
list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"
This would print "Equal" since lists have a comparison operation that is not the default returning of identity.
#Jason:
I recommend using something more along the lines of
if foo:
#foo isn't None
else:
#foo is None
I don't like using "if foo:" unless foo truly represents a boolean value (i.e. 0 or 1). If foo is a string or an object or something else, "if foo:" may work, but it looks like a lazy shortcut to me. If you're checking to see if x is None, say "if x is None:".
Some more details:
The is clause actually checks if the two objects are at the same
memory location or not. i.e whether they both point to the same
memory location and have the same id.
As a consequence of 1, is ensures whether, or not, the two lexically represented objects have identical attributes (attributes-of-attributes...) or not
Instantiation of primitive types like bool, int, string(with some exception), NoneType having a same value will always be in the same memory location.
E.g.
>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True
And since NoneType can only have one instance of itself in the python's "look-up" table therefore the former and the latter are more of a programming style of the developer who wrote the code(maybe for consistency) rather then having any subtle logical reason to choose one over the other.
John Machin's conclusion that None is a singleton is a conclusion bolstered by this code.
>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>>
Since None is a singleton, x == None and x is None would have the same result. However, in my aesthetical opinion, x == None is best.
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence
a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True

Categories

Resources