Why must I cast int to bool before checking "is True"? - python

In my url.py file in Django, I have the following line:
if bool(settings.DEBUG) is True:
This works well because settings.DEBUG == 1 therefore it equals True after the bool() function. However, I needed to add the bool() to make it work. The original line was not working and the original line was:
if settings.DEBUG is True:
This always evaluates to False, even when settings.DEBUG == 1.
Why is the value 1 evaluating to False when I do not cast it explicitly to bool?
In other words, why doesn't "1 is True" evaluate true?
Note that I am using python 3 in case that matters to the answer.

At first glance, this can be confusing as of course, the value of '1' should equal true right? However what if this int value equals '99' should this be true also?
By comparing an int with a Boolean value within the python compiler it is like comparing apples with oranges which isn't possible therefore defaulting to 'false'.
By wrapping your int value in a bool(function) you are declaring to the python compiler treat this int value as a boolean (0 == False, 1 == True) therefore it works as you intended.
Hope this helps :)

Related

Simplifying "a == True:" to "a" - is it a good idea?

PEP8 suggests the following code should be simplified.
The original
if a == True:
The suggestion
if a:
However, these two are not the same. I figured out when I followed the PEP8 recommendation. Try with the following code
import numpy as np
a = np.nan
if a == True:
print('a is True')
else:
print('a is not True')
if a:
print('a is True')
else:
print('a is not True')
And you will figure out that the first tells a is not true (correctly) while the second one incorrectly tells a is true.
a is not True
a is True
What is the point of this misleading suggestion?
You are misreading the PEP8 style guide. Here is the relevant part (emphasis mine):
Don't compare boolean values to True or False using ==:
# Correct:
if greeting:
# Wrong:
if greeting == True:
Since np.nan is not a boolean value, this advice does not apply.
Note that if you are comparing a numeric value to True, then you are normally doing something wrong in the first place. The numeric values 1 and 1.0 are both equal to True, so if you have a variable which could be either numeric or boolean, this test may give you unexpected results. It is also generally an anti-pattern to have a variable which could be either a boolean or something other than a boolean.
First off, np.nan is works the same way as float('nan').
import numpy as np
print(type(np.nan)) # <class 'float'>
Python normally says:
By default, an object is considered true unless its class defines
either a __bool__() method that returns False or a __len__() method
that returns zero, when called with the object.
Then for built-in numeric types, it says any zeros are considered False:
zero of any numeric type: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
As I bolded the only float type which is False, any other float numbers are considered True.
so :
print(bool(float('nan'))) # True
Numpy also acts like how python does.
When you say if obj: python tries to get the truth value of the obj by the help of bool() which indeed looks at __bool__ and __len__ special methods. (__bool__ has higher priority if implemented).
I would suggest to use the explicit conditional. The second option will always give you True if a!=0, besides, that type of conditionals are confusing when you didn't write the code.
This means that the variable a has a value equal to True or not.
if a == True:
But does this variable a have a value or not.
if a:

Python list indexing with bool values [duplicate]

Is it guaranteed that False == 0 and True == 1, in Python (assuming that they are not reassigned by the user)? For instance, is it in any way guaranteed that the following code will always produce the same results, whatever the version of Python (both existing and, likely, future ones)?
0 == False # True
1 == True # True
['zero', 'one'][False] # is 'zero'
Any reference to the official documentation would be much appreciated!
Edit: As noted in many answers, bool inherits from int. The question can therefore be recast as: "Does the documentation officially say that programmers can rely on booleans inheriting from integers, with the values 0 and 1?". This question is relevant for writing robust code that won't fail because of implementation details!
In Python 2.x this is not guaranteed as it is possible for True and False to be reassigned. However, even if this happens, boolean True and boolean False are still properly returned for comparisons.
In Python 3.x True and False are keywords and will always be equal to 1 and 0.
Under normal circumstances in Python 2, and always in Python 3:
False object is of type bool which is a subclass of int:
object
|
int
|
bool
It is the only reason why in your example, ['zero', 'one'][False] does work. It would not work with an object which is not a subclass of integer, because list indexing only works with integers, or objects that define a __index__ method (thanks mark-dickinson).
Edit:
It is true of the current python version, and of that of Python 3. The docs for python 2 and the docs for Python 3 both say:
There are two types of integers: [...] Integers (int) [...] Booleans (bool)
and in the boolean subsection:
Booleans: These represent the truth values False and True [...] Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively.
There is also, for Python 2:
In numeric contexts (for example when used as the argument to an arithmetic operator), they [False and True] behave like the integers 0 and 1, respectively.
So booleans are explicitly considered as integers in Python 2 and 3.
So you're safe until Python 4 comes along. ;-)
Here's the PEP discussing the new bool type in Python 2.3: http://www.python.org/dev/peps/pep-0285/.
When converting a bool to an int, the integer value is always 0 or 1, but when converting an int to a bool, the boolean value is True for all integers except 0.
>>> int(False)
0
>>> int(True)
1
>>> bool(5)
True
>>> bool(-5)
True
>>> bool(0)
False
In Python 2.x, it is not guaranteed at all:
>>> False = 5
>>> 0 == False
False
So it could change. In Python 3.x, True, False, and None are reserved words, so the above code would not work.
In general, with booleans you should assume that while False will always have an integer value of 0 (so long as you don't change it, as above), True could have any other value. I wouldn't necessarily rely on any guarantee that True==1, but on Python 3.x, this will always be the case, no matter what.

Python if statements and truth value testing for non compsci background

This aims to be a self answered question after a few hours of digging, I found this thought process may prove useful to others who also may not have come from a formal compsci background.
This all started from confusion over why one particular if statement was being entered.
>>>if (2 & 2):
... print("true")
true
Why was this if statement being entered?
My previous use of if statements were all quite straightforward, so I took it for granted and with the understanding that only a boolean True would result in the entering of an if statement. What constitutes a boolean True, was not so obvious to me after running into this if statement. This is surely obvious to those with a compsci background, but I never really dug into how if statements determined if the argument was a boolean True or not. For example, if (5 > 2) --> True just makes sense to anyone with at least an elementary-school math background, so I took it for granted. On the contrary, if (2) --> True, does not seem too obvious to a non compsci specialist.
For example
>>>2 & 2
2
>>> 2 == True
False
>>>if (2):
... print("true")
true
Why was the if statement entered despite 2 & 2 evaluating to an int value of 2? Why was the if statement entered if given the int value 2 even though 2 itself is not == True? This was the first I had seen this type of behavior and it lead me to understand from various other stack overflow questions that the if statement is not evaluating if the int value of 2 == True, but instead evaluating bool(2) == True, which is in fact True.
Again, if you come from a comp sci background, I'm sure this is all very obvious, but even the idea of bool(2) and "truth value testing" as a phrase was new to me, so adding this on to the binary logical operators caused me a fair bit of confusion at first. For example:
>>>2 & 4
0
>>>if (2 & 4):
... print("true")
>>>bin(2 & 4)
'0b0'
>>>if ('0b0'):
... print("true")
true
>>>if (0b0):
... print("true")
>>>bool(0)
False
>>>bool(0b0)
False
>>>bool(b'0')
True
>>>bool(bin(0))
True
At first, with the misunderstanding that the if statements were evaluating if the argument == True, the above examples seemed quite illogical, as I thought a binary 1 should result in True and binary 0 should result in False. I had no idea why integer values above 1, in either int or binary form should return True.
After reading through the python docs for Truth Value Testing I see a few examples of objects that are considered false. Here, and rather obviously, it makes sense why bool(0) and bool(0b0) returns False. The opposite though, for bool(b'0') and bool(bin(0)), where this seems to return True. Why is this? Because bin() returns a string representation of the number, as is b'0' (a string) not an actual binary value (like 0b0), and since these strings are not empty strings, but rather filled with the characters representing zero, it evaluates to True (See third bullet point of Truth Value Testing).
I gave a few examples of non-obvious (to me) truth evaluation tests, and why they do actually make logical sense. Hope this helps others who may be mystified by the seemingly (to me) lesser common uses of the if statement.

Python's Evaluation of If-Else Conditional Statements

I recently encountered an example of an if-else conditional statement and could not understand the rationale behind its output. The following are the statements:
if 0:
1
else:
2
Output: 2
I tried different integers in 0's place, and received 1 each time. Is this because the zero in the if condition represents False? But then why do integers other than 1 still satisfy the if condition?
Thanks!
Edit: Thank you for all your answers. I now understand that any integer except 0 in the 'if' statement will make the statement True by default, resulting in an output of 1, in this case.
Python will always attempt to determine the "truthiness" of a given value used in a boolean context. In Python any numerical value of 0 (or 0.0) is considered false, and string, dictionary, list, or other iterable (or other class that can report its length) is false if it's empty or has length of 0. Also, None and boolean False are considered false.
Other values are considered true.
More details: https://docs.python.org/2.4/lib/truth.html.
In Python, bool is a subtype of int. False has the value 0, while other non-zero integers have the subtype bool with the value True.
To see this for yourself try this: False == 0
And to see the subtypes of int try this: int.__subclasses__()
1 is considered True while 0 is False,just like in binary.
Any non-zero numeric value is evaluated as True in a conditional statement.
bool  type is just a subtype of int in Python, with 1 == True and 0 == False.

Python: why is "if <some integer>" equivalent to "if True"?

I have come across this piece of code:
counts = 128 * [0]
# some other steps here that modify the variable counts...
# in the end we have something like counts=[12, 583, 0, etc. , etc., 384]
for i in range(len(counts)):
if counts[i]:
outfile.write("%-12s%d\n" % (display(i), counts[i]))
Regarding the if statement, I understand that it is introduced so that it skips the instruction when counts[i]==0. That's because 0 is equivalent to False. But on the other side, I thought that any other integer (apart from 1) was not equivalent to True. In fact, if I type 3 == True on the shell, I get False as an answer. So, is there any particular reason why if <some integer> is equivalent to if True?
3 == True is comparing 3-as-an-integer to True-as-a-boolean.
if 3: is coercing 3 to a boolean.
You'll see that bool(3) == True is true.
Quoting docs:
Any object can be tested for truth value, for use in an if or while
condition or as operand of the Boolean operations below. The following
values are considered false:
None
False
zero of any numeric type, for example, 0, 0L, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a __nonzero__() or __len__() method, when that method returns the
integer zero or bool value False.
All other values are considered true — so objects of many types are always true.
Simple in your shell try bool(3)(which is True) and bool(0)(which is False).
bool of zero is False and bool of non-zero is True.

Categories

Resources