In python interpreter,
min(True,False)==False
max(True,False)==True
is assured by design?
True is equal to 1 and False is 0
It seems, at least in CPython, bool subclasses int. Therefore, you can do:
>>> abs(False)
0
>>> abs(True)
1
and:
>>> False < True
True
>>> True > False
True
I guess max and min work on the comparison operator:
>>> cmp(False, True)
-1
>>> cmp(True, False)
1
>>> cmp(False, False)
0
>>> cmp(True, True)
0
In python 2.x, this is not guaranteed, as you can overwrite True and False:
>>> False = 23
>>> max(True, False)
23
But if you do not assign to True or False, it is guaranteed by Language Design that Booleans subclass int with values 0, 1, yes. (and in py3, True and False are reserved words, so you cannot do the above)
According to the doc,
In numeric contexts (for example when used as the argument to an arithmetic operator), they behave like the integers 0 and 1, respectively.
So, yes, it is assured.
Related
I was checking some of CPython's tests and in this file I saw a test case which was strange to me:
def test_math(self):
...
self.assertIsNot(+False, False)
At first I thought it is a typo and it should be self.assertIs(+False, False) but when I tried it on the Python console the result was False:
>>> +False is False
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
False
>>>
>>> id(False)
140078839501184
>>> id(+False)
140078839621760
Why does + make it a different object?
Comments suggest that +False is 0. So maybe the better question should be why is this?
Because a bool is a type of int:
>>> isinstance(False, int)
True
>>> False == 0
True
a bool is accepted by functions that take ints as inputs (including all the standard operators), and those functions will generally return ints:
>>> True + False
1
>>> True * 2
2
>>> True ** False
1
or sometimes floats:
>>> True / True
1.0
Specifically, putting + in front of a number is a "unary plus", the opposite of a "unary minus" which returns the negative of its operand:
>>> +True
1
>>> -True
-1
>>> +False
0
>>> -False
0
Although this bool/int behavior catches most people off guard the first time they find it, it allows for some useful shortcuts; for example, you can sum a bunch of bools to find the number of True values:
>>> sum([True, True, False, False, True])
3
>>> sum(s.startswith("a") for s in ("apple", "banana", "pear", "avocado"))
2
When you apply arithmetic operations to boolean values they are turned into int.
In [10]: type(+False)
Out[10]: int
In [11]: type(False)
Out[11]: bool
I've come across a surprising situation when using numpy's arrays. The following code
(True==True)+(True==True)
returns 2, as one would expect. While
import numpy
Array=numpy.zeros((2,2),dtype=bool)
(Array[0][0]==Array[0][0])+(Array[1][0]==Array[1][0])
returns True. This leads to:
(Array[0][0]==Array[0][0])+(Array[1][0]==Array[1][0])-1
returning 0, while
(Array[0][0]==Array[0][0])-1+(Array[1][0]==Array[1][0])
returns 1, making the sum not commutative!
Is this intended? If so, why?
It would appear that numpy.bool_ behaves slightly differently to vanilla Python bool:
>>> int(True+True) == int(True) + int(True)
True
>>> int(numpy.bool_(1)+numpy.bool_(1)) == int(numpy.bool_(1)) + int(numpy.bool_(1))
False
This is because:
>>> True+True
2
>>> numpy.bool_(1)+numpy.bool_(1)
True
>>> int(numpy.bool_(1)+numpy.bool_(1))
1
Basically, the addition operation for numpy.bool_ is logical, rather than numerical; to get the same behaviour with bool:
>>> int(True and True)
1
This is fine if you only use it for truthiness, as intended, but if you try to use it in an integer context without being explicit about that, you end up surprised. As soon as you're explicit, expected behaviour is restored:
>>> int(numpy.bool_(1)) + int(numpy.bool_(1))
2
I think the problem is th autocasting.
in this case:
(Array[0][0]==Array[0][0])+(Array[1][0]==Array[1][0])-1
Python do:
(Array[0][0]==Array[0][0])+(Array[1][0]==Array[1][0]) = True
True -1 =cast= 1 -1 = 0
In the second case the cast is do it before:
(Array[0][0]==Array[0][0])-1+(Array[1][0]==Array[1][0])
True - 1 + True
(True - 1 =cast= 0)
0 + True =cast again= 0+ 1 = 1
So, it's not a bug. It's a autocasting in diferent parts.
As expected, 1 is not contained by the empty tuple
>>> 1 in ()
False
but the False value returned is not equal to False
>>> 1 in () == False
False
Looking at it another way, the in operator returns a bool which is neither True nor False:
>>> type(1 in ())
<type 'bool'>
>>> 1 in () == True, 1 in () == False
(False, False)
However, normal behaviour resumes if the original expression is parenthesized
>>> (1 in ()) == False
True
or its value is stored in a variable
>>> value = 1 in ()
>>> value == False
True
This behaviour is observed in both Python 2 and Python 3.
Can you explain what is going on?
You are running into comparison operator chaining; 1 in () == False does not mean (1 in ()) == False.
Rather, comparisons are chained and the expression really means:
(1 in ()) and (() == False)
Because (1 in ()) is already false, the second half of the chained expression is ignored altogether (since False and something_else returns False whatever the value of something_else would be).
See the comparisons expressions documentation:
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).
For the record, <, >, ==, >=, <=, !=, is, is not, in and not in are all comparison operators (as is the deprecated <>).
In general, don't compare against booleans; just test the expression itself. If you have to test against a boolean literal, at least use parenthesis and the is operator, True and False are singletons, just like None:
>>> (1 in ()) is False
True
This gets more confusing still when integers are involved. The Python bool type is a subclass of int1. As such, False == 0 is true, as is True == 1. You therefor can conceivably create chained operations that almost look sane:
3 > 1 == True
is true because 3 > 1 and 1 == True are both true. But the expression:
3 > 2 == True
is false, because 2 == True is false.
1 bool is a subclass of int for historic reasons; Python didn't always have a bool type and overloaded integers with boolean meaning just like C does. Making bool a subclass kept older code working.
As expected, 1 is not contained by the empty tuple
>>> 1 in ()
False
but the False value returned is not equal to False
>>> 1 in () == False
False
Looking at it another way, the in operator returns a bool which is neither True nor False:
>>> type(1 in ())
<type 'bool'>
>>> 1 in () == True, 1 in () == False
(False, False)
However, normal behaviour resumes if the original expression is parenthesized
>>> (1 in ()) == False
True
or its value is stored in a variable
>>> value = 1 in ()
>>> value == False
True
This behaviour is observed in both Python 2 and Python 3.
Can you explain what is going on?
You are running into comparison operator chaining; 1 in () == False does not mean (1 in ()) == False.
Rather, comparisons are chained and the expression really means:
(1 in ()) and (() == False)
Because (1 in ()) is already false, the second half of the chained expression is ignored altogether (since False and something_else returns False whatever the value of something_else would be).
See the comparisons expressions documentation:
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).
For the record, <, >, ==, >=, <=, !=, is, is not, in and not in are all comparison operators (as is the deprecated <>).
In general, don't compare against booleans; just test the expression itself. If you have to test against a boolean literal, at least use parenthesis and the is operator, True and False are singletons, just like None:
>>> (1 in ()) is False
True
This gets more confusing still when integers are involved. The Python bool type is a subclass of int1. As such, False == 0 is true, as is True == 1. You therefor can conceivably create chained operations that almost look sane:
3 > 1 == True
is true because 3 > 1 and 1 == True are both true. But the expression:
3 > 2 == True
is false, because 2 == True is false.
1 bool is a subclass of int for historic reasons; Python didn't always have a bool type and overloaded integers with boolean meaning just like C does. Making bool a subclass kept older code working.
Indexing on list with boolean values works fine.
Though the index should be an integer.
Following is what I tried in console:
>>> l = [1,2,3,4,5,6]
>>>
>>> l[False]
1
>>> l[True]
2
>>> l[False + True]
2
>>> l[False + 2*True]
3
>>>
>>> l['0']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list indices must be integers, not str
>>> type(True)
<type 'bool'>
When I tried l['0'] it printed error that int type expected in indices and that is obvious.
Then, even the type of 'True' and 'False' being Bool, indexing on the list works fine and automatically converts it to int type and performs the operation.
Please explain what is going on internally.
I am posting question for the first time, so please forgive me for any mistake.
What's going on is that booleans actually are integers. True is 1 and False is 0. Bool is a subtype of int.
>>> isinstance(True, int)
True
>>> issubclass(bool, int)
True
So it's not converting them to integers, it's just using them as integers.
(Bools are ints for historical reasons. Before a bool type existed in Python, people used the integer 0 to mean false and 1 to mean true. So when they added a bool type, they made the boolean values integers in order to maintain backward compatibility with old code that used these integer values. See for instance http://www.peterbe.com/plog/bool-is-int .)
>>> help(True)
Help on bool object:
class bool(int)
| bool(x) -> bool
|
| Returns True when the argument x is true, False otherwise.
| The builtins True and False are the only two instances of the class bool.
| The class bool is a subclass of the class int, and cannot be subclassed.
Python used to lack booleans, we just used integers, 0 for False and any other integer for True. So when booleans were added to the language, the values False and True, can be treated as the integer values 0 and 1 still by the interpreter, to help backwards compatibility. Internally, bool is a sub-class of int.
In other words, the following equations are True:
>>> False == 0
True
>>> True == 1
True
>>> isinstance(True, int)
True
>>> issubclass(bool, int)
True
and as you found out:
>>> True * 3
3
This doesn't extend to strings however.
...Booleans are a subtype of plain integers.
Source.
As you can see, False is 0 and True is 1.
The Python source documentation does not mention directly that all non-zero integers are evaluate to True when passed to an if statement, while only zero evaluates to False. You can prove it to yourself with the following code in Python:
for test_integer in range(-2, 3, ):
if not test_integer:
print('{} evaluates to False in Python.'.format(test_integer))
else:
print('{} evaluates to True in Python.'.format(test_integer))
>>>-2 evaluates to True in Python.
-1 evaluates to True in Python.
0 evaluates to False in Python.
1 evaluates to True in Python.
2 evaluates to True in Python.
Try it for as far on either side of zero as you want; this code only shows for -2, -1, 0, 1, and 2 inclusive.