Python evaluates 0 as False - python

In the Python console:
>>> a = 0
>>> if a:
... print "L"
...
>>> a = 1
>>> if a:
... print "L"
...
L
>>> a = 2
>>> if a:
... print "L"
...
L
Why does this happen?

In Python, bool is a subclass of int, and False has the value 0; even if values weren't implicitly cast to bool in an if statement (which they are), False == 0 is true.

0 is a falsy value in python
Falsy values: from (2.7) documentation:
zero of any numeric type, for example, 0, 0L, 0.0, 0j.

Whatever is inside an if clause implicitly has bool called on it. So,
if 1:
...
is really:
if bool(1):
...
and bool calls __nonzero__1 which says whether the object is True or False
Demo:
class foo(object):
def __init__(self,val):
self.val = val
def __nonzero__(self):
print "here"
return bool(self.val)
a = foo(1)
bool(a) #prints "here"
if a: #prints "here"
print "L" #prints "L" since bool(1) is True.
1__bool__ on python3.x

I think it just judges by 0 or not 0:
>>> if 0:
print 'aa'
>>> if not 0:
print 'aa'
aa
>>>

First of all, everything in python is an object. Therefore, your 0 is also an object, specifically, a built-in object.
Here are the built-in objects considered as false:
constants defined to be false: None and False.
zero of any numeric type: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
empty sequences and collections: '', (), [], {}, set(), range(0)
So when you put 0 in an if or while condition, or in a Boolean operation, it is tested for truth value.
# call the __bool__ method of 0
>>> print((0).__bool__())
False
#
>>> if not 0:
... print('if not 0 is evaluated as True')
'if not 0 is evaluated as True'

Related

Comparing None to several variables in Python3

Is there anyone that can tell my why I get this type of return value?
>>> a = 7
>>> b = None
>>> bool(a and b)
False
>>> bool((a is None) and (b is None))
False
>>> bool((a and b) is None) # (a and b) eq False
True
>>> bool(False is None)
False
I just can't understand why this is happening.
To explain
>>> 7 and None
None
>>> bool(None)
False
So to answer:
a and b gives None and not False as you put in comment.
bool(a and b) gives False
So then when you replace a and b by its real value:
you get bool(None is None) which is True.
I believe you had bool(bool(a and b) is None) in mind, which would give False
Python's and actually returns the last value tested. For x and y, if x is false, it will return x; if x is true, it will return y. For example:
>>> 0 and ''
0
>>> 0 and 'x'
0
>>> 1 and ''
''
>>> 1 and 'x'
'x'
So when you do a and b, you get None.
Source: Documentation: Boolean Operations — and, or, not
All Python builtins and most instances have implicit truth values thanks to their __bool__ magic methods. In your case, you are working with the builtin types of int and None. In pure python, the __bool__ method for an int would like something like the following:
class int(object):
...
def __bool__(self):
return self != 0 # True as long as not equal to 0
...
And for a None it would be the following:
class NoneType(object):
...
def __bool__(self):
return False # Always False
...
Whenever an operation is done that requires the variable to be treated as a boolean (and, or, not, bool casting), these __bool__ magic methods are used to get their corresponding instance's truth value.
So with this in mind, let's look at your expressions one-by-one.
>>> bool(a and b)
False
a is the integer 7, so by its __bool__ magic method, it has a positive truth value (True). b is None, and it has a negative truth value (False). When you and variables in Python, if the first and operand has a positive truth value, and will always return the second operand (the opposite behavior can be seen with or). More information on this can be found here. So when you do a and b, None is returned because a has a positive truth value. The resulting None is then casted to a bool which as shown in None's __bool__ method above, will be False.
>>> bool((a is None) and (b is None))
False
This evaluates to False as a is not None. Here, since you are using is in the statements, you are not comparing truth value, but you are checking if they are the same object. Since 7 and None are not the same instance, it results to False, causing the rest of the statement to evaluate to False.
>>> bool((a and b) is None) # (a and b) eq False (should be None)
True
Following up from the first one, a and b will return None. since None is the same instance as None, None is None evaluates to True. The casting to bool is redundant.
>>> bool(False is None)
False
Lastly, here we are once again checking if False and None are the same instance. As they are not, this evaluates to False and the casting to bool is once again redundant.
Consider these two facts:
None is false
and returns true if both variables are true.
In every case that misleads you, you did not consider these facts.

How come I can add the boolean value False but not True in a set in Python? [duplicate]

This question already has answers here:
Python set class, float and int evaluation
(1 answer)
Why is bool a subclass of int?
(3 answers)
Closed 4 years ago.
I just started investigating the set data type in Python. For some reason, whenever I add the Boolean value of True to a set it doesn't appear. However, if I add False to a set it will become an element of the set. I was shocked when I googled this question that nothing came up.
example1 = {1, 2, 7, False}
example2 = {7, 2, 4, 1, True}
print(example1)
print(example2)
The output is:
{False, 1, 2, 7}
{1, 2, 4, 7}
Because in Python 1 == True (and hash(1) == hash(True)) and you have 1 in your set already.
Imagine this example:
example1 = {0, False, None}
example2 = {1, True}
print(example1)
print(example2)
Will output:
{0, None}
{1}
First set has 0 and None because 0 == False but 0 != None. With second set 1 == True so True isn't added to the set.
The reason that you are losing boolean values from a set if they already contain 0 or 1 is because the following behavior...
>>> hash(1) == hash(True)
True
>>> hash(0) == hash(False)
True
>>> 1 == True
>>> True
>>> 0 == False
>>> True
...is guaranteed in Python 3.x.
Which means that you cannot have both in a set:
>>> set([True, 1])
{True}
>>> set([False, 0])
{False}
The hashes being equal is just as important as the objects being equal, because objects that are "equal" can produce different hashes and vice versa:
class Foo:
def __init__(self, x): self.x = x
def __hash__(self): return 1
def __eq__(self, other): return self.x == other.x
class Bar:
def __init__(self, x): self.x = x
def __hash__(self): return 2
def __eq__(self, other): return self.x == other.x
>>> x = Foo(3)
>>> y = Bar(3)
>>> x == y
True
>>> hash(x) == hash(y)
False
>>> set([x, y])
{<__main__.Bar at 0x56ed278>, <__main__.Foo at 0x5707390>}
You can also have a set that contains items with the same hashes, if those items are not equal:
>>> hash('a')
-904409032991049157
>>> hash(-904409032991049157)
-904409032991049157
>>> hash('a') == hash(-904409032991049157)
True
>>> set(['a', -904409032991049157])
{-904409032991049157, 'a'}
This behavior is not guaranteed in Python 2.x, for the simple reason that True and False are not reserved keywords (this change was introduced in 3.x). You may reassign them (although better not to), so there is no reason that the same behavior must hold in Python 2.x:
>>> True = 5
>>> hash(True) == hash(1)
False
>>> set([1, True])
set([1, 5])
But don't let the fact that True was replaced with 5 discourage you! We can abuse the representation of a class to make it appear as though True really is in the set:
class Foo(object):
def __repr__(self):
return('True')
>>> True = Foo()
>>> set([1, True])
set([1, True])
Obviously the last couple code snippets are bad practice, and are only for demonstration. The main takeaway is that equal objects with the same hash cannot be contained in the same set, and in Python 3.x, 1 and True, and 0 and False, will always have the same hash, and will always be equal.
False and True are equal to 0 and 1, respectively. They are distinct entities, yet the two equal values cannot both be in a set. This is clearly undesired behavior, yet it is not clear it can be fixed and still allow multiplying by a boolean value to work as documented.
IPython 6.2.1 -- An enhanced Interactive Python.
1 is True
Out[1]: False
{1,True}
Out[2]: {1}
{0,False}
Out[3]: {0}
{False, 0}
Out[4]: {False}
{True, 1}
Out[5]: {True}
Notice that depending on the order of putting them into the set, 1 will not be in the set if True is already in it, and True will not be in the set if 1 is already in it.

What does not int(x) do?

I have trouble understanding the meaning of not in a statement such as
not int(x)
It evaluates to True if x is equal to 0.
But if x is any other number it evaluates to False.
I would like an explanation for this behavior, thanks.
not some_object will return True if some_object is falsy, i.e. if bool(some_object) will return False.
For any integer z, bool(z) will always be True unless z==0. So not int(x) is just a way of checking whether x, after you convert it to an integer (using int), is zero.
Demo:
>>> x = '-7' # this is not 0 after conversion to an integer
>>> bool(int(x))
True
>>> x = '0'
>>> bool(x) # a non-empty string is truthy
True
>>> bool(int(x))
False
>>> not int(x) # you can omit the call to bool in a boolean context
True
In a boolean context, we can omit the call to bool. Using the implicit booleanness of objects can come in handy, especially when you want to check if some object is empty (such as empty strings, sets, lists, dictionaries...).
>>> not {}
True
>>> not []
True
>>> not set()
True
>>> not ''
True
>>> not tuple()
True
>>> not 0.0
True
>>> not 0j
True
>>> not [1,2,3]
False
The methods involved here are __nonzero__ for Python2 and __bool__ for Python3. Theoretically, we could override these. Consider the following Python2 example:
>>> class LyingList(list):
... def __nonzero__(self): # for Py3, override __bool__
... return True
...
>>> liar = LyingList([])
>>> liar
[]
>>> not liar
False
uh oh!

Test for actual equality in Python

I am writing a Python2 module that emulates a certain library. The results may be float, int, long, unicode, str, tuple, list, and custom objects. Lists may not contain lists, but they may contain tuples. Tuples may not contain lists or tuples. Otherwise, lists and tuples may contain any of the other types listed above.
(Actually, the module should not return long or str, but if it does, they should be caught and reported as different when compared to int and unicode, respectively.)
I am writing a testing program that checks the results against known answers by the library my module tries to emulate. The obvious answer would be to test the values and the types, but one problem I'm facing is that in corner cases, possible results to test for are -0.0 (which should be distinguished from 0.0) and NaN (Not a Number - a value a float can take).
However:
>>> a = float('nan')
>>> b = float('nan')
>>> a == b
False
>>> c = float('-0.0')
>>> c
-0.0
>>> d = 1.0 - 1.0
>>> c == d
True
The is operator doesn't help a bit:
>>> a is b
False
>>> d is 0.0
False
repr helps:
>>> repr(a) == repr(b)
True
>>> repr(c) == repr(d)
False
>>> repr(d) == repr(0.0)
True
But only to a point, since it doesn't help with objects:
>>> class e:
... pass
...
>>> f = e()
>>> g = e()
>>> f.x = float('nan')
>>> g.x = float('nan')
>>> f == g
False
>>> repr(f) == repr(g)
False
This works though:
>>> repr(f.__dict__) == repr(g.__dict__)
True
But it fails with tuples and lists:
>>> h = [float('nan'), f]
>>> i = [float('nan'), g]
>>> h == i
False
>>> repr(h) == repr(i)
False
>>> repr(h.__dict__) == repr(i.__dict__)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__dict__'
It seems I'm close, so I need to know:
Is there a simpler way to check for actual equality that doesn't have the burden of converting to string?
If not, how would I go about comparing lists or tuples containing objects?
Edit: To be clear, what I'm after is a full comparison function. My test function looks roughly like this:
>>> def test(expression, expected):
... actual = eval(expression)
... if not reallyequal(actual, expected):
... report_error(expression, actual, expected)
My question concerns what should reallyequal() look like.
Edit 2: I've found the Python standard module unittest but unfortunately none of the checks covers this use case, so it seems that if I intend to use it, I should use something like self.assertTrue(reallyequal(actual, expected)).
I'm actually surprised that it's so hard to make unit tests including expected NaNs and minus zeros nested within the results. I'm still using the repr solution which is a half-solution, but I'm open to other ideas.
Here is one implementation:
def really_equal(actual, expected, tolerance=0.0001):
"""Compare actual and expected for 'actual' equality."""
# 1. Both same type?
if not isinstance(actual, type(expected)):
return False
# 2. Deal with floats (edge cases, tolerance)
if isinstance(actual, float):
if actual == 0.0:
return str(actual) == str(expected)
elif math.isnan(actual):
return math.isnan(expected)
return abs(actual - expected) < tolerance
# 3. Deal with tuples and lists (item-by-item, recursively)
if isinstance(actual, (tuple, list)):
return all(really_equal(i1, i2) for i1, i2 in zip(actual, expected))
# 4. Fall back to 'classic' equality
return actual == expected
A few of your edge cases from "classic" equality:
>>> float('nan') == float('nan')
False
>>> really_equal(float('nan'), float('nan'))
True
>>> 0.0 == -0.0
True
>>> really_equal(0.0, -0.0)
False
>>> "foo" == u"foo"
True
>>> really_equal("foo", u"foo")
False
>>> 1L == 1
True
>>> really_equal(1L, 1)
False
Classes should implement their own __eq__ "magic method" to determine whether or not two instances are equal - they will fall through to # 4 and be compared there:
>>> class Test(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
>>> a = Test(1)
>>> b = Test(1)
>>> really_equal(a, b)
True
From the answers and comments it seems clear that the answer to my first question (is there a simpler way than using repr()?) is no, there is no simpler way. So I've researched more on how to accomplish this as simply as possible and I've come up with this solution which answers my second question.
repr() works for the most part, but fails on objects of custom classes. Since the default repr() of a custom object is not useful as-is anyway for any meaningful purpose, what I've done is to override the __repr__ method of each base class like this:
class MyClass:
def __repr__(self):
return self.__class__.__name__ + "(" \
+ repr(sorted(self.__dict__.items(), key=lambda t: t[0])) + ")"
Now I can use repr() on any of the values and get an expression that actually represents these values uniquely, that my test program can catch.
def reallyequal(actual, expected):
return repr(actual) == repr(expected)
(which I will actually embed in the test function due to its simplicity).
Here it is in action:
>>> reallyequal(-0.0, 0.0)
False
>>> reallyequal(float('nan'),float('nan'))
True
>>> f = MyClass()
>>> f.x = float('nan')
>>> g = MyClass()
>>> g.x = float('nan')
>>> reallyequal(f, g)
True
>>> h = [f,3]
>>> i = [g,4]
>>> reallyequal(h, i)
False
>>> i[1] = 3
>>> reallyequal(h, i)
True
>>> g.x = 1
>>> reallyequal(h, i)
False
>>> f.x = 1L
>>> reallyequal(h, i)
False
>>> f.x = 1
>>> reallyequal(h, i)
True
Edit: Edited to incorporate commenter's suggestions re repr results with __dict__.

Difference between 'not x' and 'x==None' in 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.

Categories

Resources