Why can we cast bool to str? - python

We know how bool() acts on various python objects such as str, int, list.
This is a question about the reverse.
You can cast bool to int as
>>> int(True)
1
>>> int(False)
0
which I think kinda makes sense, but with string we get
>>> str(False)
'False'
>>> str(True)
'True'
which I don't get, as firstly it seems to imply some relation between False and 'False', which only seems relevant at the code level. If what is written in code is to be treated this way, how does this work ...
>>> str(not True)
'False'
Second, it's not obvious it's for consistency, as
>>> bool(str(False))
True
My question is ... is there a reason we're allowed to cast bool to str in this way? list for example won't allow it ...
>>> list()
[]
>>> bool()
False
>>> bool(list())
False
>>> list(bool())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bool' object is not iterable

For debugging. If you can't cast a thing to a string, you can't print it. If you want to print a data structure for debugging, you need to be able to cast each element to a string. That's what str is documented to do...
Return a string containing a nicely printable representation of an object.
If what is written in code is to be treated this way, how does this work ...
>>> str(not True)
'False'
not True resolves to False which is then passed to str. It's similar to how with foo(1 + 1) foo receives 2.
Second, it's not obvious it's for consistency, as
>>> bool(str(False))
True
Casting is not guaranteed to round trip. Examples are int(float(2.34)) or int(unichr(97)).
There's an important difference between converting something to a string for humans, which is what str does, and converting something to a string for marshalling which must round trip. There are specialized packages like marshal or json for marshalling.
But casting is the wrong way to think about bool and str in Python. As above, str returns a printable representation, not a machine-readable one. bool is for asking "what is the truthiness of this expression"? From the docs...
x is converted using the standard truth testing procedure.
"True" and "False" are both true. If they added a special case just for bool that would be very inconsistent.

str() and bool() are not "casts", they're constructors (type objects). Calling str(x) for any value x will construct a new str object with its value initialized (somehow) from x. There is no implied relationship between the two objects; str(x) could return anything as long as it is a str object.
Basically: stop thinking of Python as having "casts" like other languages you may be used to. Constructors are just another kind of callable, and the general rule is for each type to do something sensible with the argument(s) passed to the constructor. In the case of str(), it delegates to the __str__ special method if present, which means that bool objects return the strings 'True' and 'False' because that's what the bool type decided to do.

Well, what is the problem with str(True) being 'True'? That's quite the expected.
Now, if you convert boolean to integer, it's obvious that the result must be a number.
And, naturally, not True evaluates to False. That is str(False), then: 'False'.
About the bool() function, it's supposed to return True for anything that is not empty, zero, None or False.
So any string that is not '' fits this and returns True. See more: https://docs.python.org/3/library/stdtypes.html#truth

There is a very limited set of things considered False in Python:
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
So if you do bool(something) it will only return False for those items. Everything else in Python is True including string representations of falsy things: '0' 'False', 'None' etc because the string itself is True.

Related

Why does ... == True return False in Python 3?

I am learning python, but I'm a bit confused by the following result.
In [41]: 1 == True
Out[41]: True
In [42]: if(1):
...: print('111')
...:
111
In [43]: ... == True
Out[43]: False <===== why this is False while '1 == True' is True in previous sample
In [44]: if (...): <==== here ... just behaves like True
...: print('...')
...:
...
According to the documentation, ... has a truth value of True.
But I still feel the above code a bit inconsistent.
...And something more interesting:
In [48]: 2==True
Out[48]: False <===== why 1==True returns True while 2==True returns False?
In [49]: if(2):
...: print('222')
...:
222
You're mixing two concepts: equality testing and truth-value testing. They are not the same in Python.
I think what triggered the question is that Python does an implicit casting when you do if something (it casts the something to bool) but it does not do implicit casting when you do something1 == something2.
Pythons data model actually explains how these operations are done:
Truth-value testing
It starts by checking if the object implements the __bool__ method and if it does it uses the returned boolean.
If it doesn't define a __bool__ method it looks at the __len__ method. If it's implemented it will use the result of len(obj) != 0.
If it doesn't have either the object is considered True.
For integers the __bool__ method returns True except when the integer value is 0 (then it's False).
The Ellipsis object (... is the Ellipsis object) on the other hand doesn't implement __bool__ or __len__ so it's always True.
Equality testing
Equality testing relies on the __eq__ method of both arguments. It's more a chain of operations:
It checks if the first operand implements __eq__ when the second operand is passed as argument.
If it doesn't then it checks if the second operand implements __eq__ when the first operand is passed as argument.
If it doesn't then Python checks for object identity (if they are the same object - similar to pointer comparisons in C-like languages)
The order of these operations may vary.1
For built-in Python types these operations are explicitly implemented. For example integers implement __eq__ but the CHECK_BINOP makes sure that it returns NotImplemented if the other one isn't an integer.
The Ellipsis object doesn't implement __eq__ at all.
So when you compare integers and Ellipsis Python will always fallback to object identity and so it will always return False.
On the other hand booleans are a subclass of integers so they actually compare with int (they are another int after all). The booleans are implemented as 1 (True) and 0 (False). So they compare equal:
>>> 1 == True
True
>>> 0 == False
True
>>> 1 == False
False
>>> 0 == True
False
Even though the source code is probably hard to understand I hope I explained the concepts well enough (the source code is for the CPython implementation, the implementation in other Python implementations like PyPy, IronPython may differ!). The important take-away message should be that Python doesn't do implicit conversions in equality checks and equality testing is not related to truth value testing at all. The built-in types are implemented that they almost always give senseable results:
all number-types implement equality in some way (floats compare to integers, complex compare to integers and floats)
and everything not-zero and not-empty is truthy.
However if you create your own classes you can override equality and truth value testing as you like (and then you can spread a lot of confusion)!
1 In some cases the order is changed:
If the second operand is a subclass of the first operand the first two steps are reversed.
For some implicit equality checks the object identity is checked before any __eq__ methods are called. For example when checking if some item is in a list, i.e. 1 in [1,2,3].
Any object can be tested for "truthiness":
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, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a bool() or len() method, when that method returns the integer zero or bool value False. [1]
All other values are considered true — so objects of many types are always true.
Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations or and and always return one of their operands.)
So it's not hard to see that if ... will enter the branch. The Ellipsis object is considered true. However that doesn't mean it has to be equal to True. Just the bool(...) == True!
The if will implicitly call bool on the condition, so:
if ...:
# something
will be evaluated as if you had written:
if bool(...):
# something
and:
>>> bool(...)
True
>>> bool(1)
True
>>> bool(2)
True
However there's one catch here. True is equal to 1 and False equal to 0, but that's just because bool subclasses integer in python.
In python most (all?) objects have a bool value. The meaning behind "has a truth value of True" means that bool(obj) evaluates to True.
On the other hand, True is treated as 1 in many cases (and False as 0) which you can see when you do stuff like:
sum([True, True, False])
# (1 + 1 + 0) -> 2
That is why you get 1 == True --> True
There is a more explicit explanation in the documentation:
Boolean values are the two constant objects False and True. They are used to represent truth values (although other values can also be considered false or true). In numeric contexts (for example when used as the argument to an arithmetic operator), they behave like the integers 0 and 1, respectively
From the type-hierarchy itself in the docs:
These represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of the integer type, and 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.
I believe it's 1 == True here is that's weird, not that ... != True.
1 equals with True because in Python booleans are subclass of integers (because of PEP-285). See yourself:
>>> issubclass(bool, int)
True

If statement with no logical operators in python

I have the following python code:
value = 1.9
if value:
#do something
else:
#do something else
What happens here? I can't understand this because value is not Boolean.
Python has a concept of truthy-ness where non-Boolean values are basically "coerced" into Boolean ones, as shown here:
4.1 Truth value testing
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, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a __bool__() 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.
Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated. (Important exception: the Boolean operations or and and always return one of their operands.)
Bottom line is that 1.9 comes under the "All other values are considered true" clause since it matches none of the values that would be considered false. The closest it comes is the third one (numeric type) but, since it's non-zero, it doesn't quite get there.
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
https://docs.python.org/2.4/lib/truth.html
So since value isn't one of those things, it takes the if, not the else!
Check this documentation materials. In python as in many programming language. 0, '', [] kind of values gives False while any other value returns True.
It is going to be False only if value is equal 0 or ""

Why is bool(x) where x is any integer equal to True

I expected bool(1) to equate to True using Python - it does - then I expected other integers to error when converted to bool but that doesn't seem to be the case:
>>> x=23 #<-- replace with any integer
>>> bool(x)
True
What is happening? Am I misunderstanding bool(x) - does this not convert x to a Boolean data type?
A lot of comments about why I find this counter-intuitive. If I write the above like the below then, on first sight with no knowledge of the language, it would seem counter-intuitive:
>>>True == bool(23)
True
From 5.1 Truth Value Testing:
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.
bool(x) converts its argument to Bool by using the standard truth testing procedure. Anything that would return true on an if test, for example, will return True when passed as the argument to bool.
Check Truth Value Testing to see which values are treated as True or False in Python
bool's purpose is not to convert a value to the bool data type, per se. Rather, it returns whether the value is truthy, i.e. it behaves in the same manner that this function does:
def bool_mimic(val):
if val:
return True
else:
return False
From the docs:
bool([x])
Convert a value to a Boolean, using the standard truth testing procedure [see Rohit's answer]. If x is false or omitted, this returns False; otherwise it returns True. bool is also a class, which is a subclass of int. Class bool cannot be subclassed further. Its only instances are False and True.
In the case of ints, the only non-truthy integer is 0.
As other posters have mentioned, its giving true on any non-zero integer.
Its kind of similar to other things in python, like mentioned here:
Python 'If not' syntax
(Rohit quotes a good paragraph about truth testing)

Python things which are neither True nor False

I just found this :
a = (None,)
print (a is True)
print (a is False)
print (a == True)
print (a == False)
print (a == None)
print (a is None)
if a : print "hello"
if not a : print "goodbye"
which produces :
False
False
False
False
False
False
hello
So a neither is, nor equals True nor False, but acts as True in an if statement.
Why?
Update :
actually, I've just realized that this isn't as obscure as I thought. I get the same result for a=2, as well (though not for a=0 or a=1, which are considered equal to False and True respectively)
I find almost all the explanations here unhelpful, so here is another try:
The confusion here is based on that testing with "is", "==" and "if" are three different things.
"is" tests identity, that is, if it's the same object. That is obviously not true in this case.
"==" tests value equality, and obviously the only built in objects with the values of True and False are the object True and False (with the exception of the numbers 0 and 1, of any numeric type).
And here comes the important part:
'if' tests on boolean values. That means that whatever expression you give it, it will be converted to either True or False. You can make the same with bool(). And bool((None,)) will return True. The things that will evaluate to False is listed in the docs (linked to by others here)
Now maybe this is only more clear in my head, but at least I tried. :)
a is a one-member tuple, which evaluates to True. is test identity of the object, therefore, you get False in all those test. == test equality of the objects, therefore, you get False again.
in if statement a __bool__ (or __nonzero__) used to evaluate the object, for a non-empty tuple it should return True, therefore you get True. hope that answers your question.
edit: the reason True and False are equal to 1 and 0 respectively is because bool type implemented as a subclass of int type.
Things in python don't have to be one of True or False.
When they're used as a text expression for if/while loops, they're converted to booleans. You can't use is or == to test what they evaluate to. You use bool( thing )
>>> a = (None,)
>>> bool(a)
True
Also note:
>>> 10 == True
False
>>> 10 is True
False
>>> bool(10)
True
TL;DR:
if and == are completely different operations. The if checks the truth value of a variable while == compares two variables. is also compares two variables but it compares if both reference the same object.
So it makes no sense to compare a variable with True, False or None to check it's truth value.
What happens when if is used on a variable?
In Python a check like if implicitly gets the bool of the argument. So
if something:
will be (under the hood) executed like:
if bool(something):
Note that you should never use the latter in your code because it's considered less pythonic and it's slower (because Python then uses two bools: bool(bool(something))). Always use the if something.
If you're interested in how it's evaluated by CPython 3.6:
Note that CPython doesn't exactly use hasattr here. It does check if the type of x implements the method but without going through the __getattribute__ method (hasattr would use that).
In Python2 the method was called __nonzero__ and not __bool__
What happens when variables are compared using ==?
The == will check for equality (often also called "value equality"). However this equality check doesn't coerce the operands (unlike in other programming languages). The value equality in Python is explicitly implemented. So you can do:
>>> 1 == True # because bool subclasses int, True is equal to 1 (and False to 0)
True
>>> 1.0 == True # because float implements __eq__ with int
True
>>> 1+1j == True # because complex implements __eq__ with int
True
However == will default to reference comparison (is) if the comparison isn't implemented by either operand. That's why:
>>> (None, ) == True
False
Because tuple doesn't "support" equality with int and vise-versa. Note that even comparing lists to tuples is "unsupported":
>>> [None] == (None, )
False
Just in case you're interested this is how CPython (3.6) implements equality (the orange arrows indicate if an operation returned the NotImplemented constant):
That's only roughly correct because CPython also checks if the type() of value1 or value2 implements __eq__ (without going through the __getattribute__ method!) before it's called (if it exists) or skipped (if it doesn't exist).
Note that the behavior in Python2 was significantly more lengthy (at least if the methods returned NotImplemented) and Python 2 also supported __cmp__,
What happens when variables are compared using is?
is is generally referred to as reference equality comparison operator. It only returns True if both variables refer to exactly the same object. In general variables that hold the same value can nevertheless refer to different objects:
>>> 1 is 1. # same value, different types
False
>>> a = 500
>>> a is 500 # same value, same type, different instances
False
Note that CPython uses cached values, so sometimes variables that "should" be different instances are actually the same instance. That's why I didn't use 500 is 500 (literals with the same value in the same line are always equal) and why I couldn't use 1 as example (because CPython re-uses the values -5 to 256).
But back to your comparisons: is compares references, that means it's not enough if both operands have the same type and value but they have to be the same reference. Given that they didn't even have the same type (you're comparing tuple with bool and NoneType objects) it's impossible that is would return True.
Note that True, False and None (and also NotImplemented and Ellipsis) are constants and singletons in CPython. That's not just an optimization in these cases.
(None,) is a tuple that contains an element, it's not empty and therefore does not evaluate to False in that context.
Because a=(None,) is a tuple containing a single element None
Try again with a=None and you will see there is a different result.
Also try a=() which is the empty tuple. This has a truth value of false
In Python every type can be converted to bool by using the bool() function or the __nonzero__ method.
Examples:
Sequences (lists, strings, ...) are converted to False when they are empty.
Integers are converted to False when they are equal to 0.
You can define this behavior in your own classes by overriding __nonzero__().
[Edit]
In your code, the tuple (None,) is converted using bool() in the if statements. Since it's non-empty, it evaluates to True.

How do I use a Boolean in Python?

Does Python actually contain a Boolean value? I know that you can do:
checker = 1
if checker:
#dostuff
But I'm quite pedantic and enjoy seeing booleans in Java. For instance:
Boolean checker;
if (someDecision)
{
checker = true;
}
if(checker)
{
//some stuff
}
Is there such a thing as a Boolean in Python? I can't seem to find anything like it in the documentation.
checker = None
if some_decision:
checker = True
if checker:
# some stuff
[Edit]
For more information: http://docs.python.org/library/functions.html#bool
Your code works too, since 1 is converted to True when necessary.
Actually Python didn't have a boolean type for a long time (as in old C), and some programmers still use integers instead of booleans.
The boolean builtins are capitalized: True and False.
Note also that you can do checker = bool(some_decision) as a bit of shorthand -- bool will only ever return True or False.
It's good to know for future reference that classes defining __nonzero__ or __len__ will be True or False depending on the result of those functions, but virtually every other object's boolean result will be True (except for the None object, empty sequences, and numeric zeros).
True ... and False obviously.
Otherwise, None evaluates to False, as does the integer 0 and also the float 0.0 (although I wouldn't use floats like that).
Also, empty lists [], empty tuplets (), and empty strings '' or "" evaluate to False.
Try it yourself with the function bool():
bool([])
bool(['a value'])
bool('')
bool('A string')
bool(True) # ;-)
bool(False)
bool(0)
bool(None)
bool(0.0)
bool(1)
etc..
Boolean types are defined in documentation:
http://docs.python.org/library/stdtypes.html#boolean-values
Quoted from doc:
Boolean values are the two constant objects False and True. They are used to represent truth values (although other values can also be considered false or true). In numeric contexts (for example when used as the argument to an arithmetic operator), they behave like the integers 0 and 1, respectively. The built-in function bool() can be used to cast any value to a Boolean, if the value can be interpreted as a truth value (see section Truth Value Testing above).
They are written as False and True, respectively.
So in java code remove braces, change true to True and you will be ok :)
Yes, there is a bool data type (which inherits from int and has only two values: True and False).
But also Python has the boolean-able concept for every object, which is used when function bool([x]) is called.
See more: object.nonzero and boolean-value-of-objects-in-python.
Unlike Java where you would declare boolean flag = True, in Python you can just declare myFlag = True
Python would interpret this as a boolean variable
Booleans in python are subclass of integer. Constructor of booleans is bool. bool class inherits from int class.
issubclass(bool,int) // will return True
isinstance(True,bool) , isinstance(False,bool) //they both True
True and False are singleton objects. they will retain same memory address throughout the lifetime of your app. When you type True, python memory manager will check its address and will pull the value '1'. for False its value is '0'.
Comparisons of any boolean expression to True or False can be performed using either is (identity) or == (equality) operator.
int(True) == 1
int(False) == 0
But note that True and '1' are not the same objects. You can check:
id(True) == id(1) // will return False
you can also easily see that
True > False // returns true cause 1>0
any integer operation can work with the booleans.
True + True + True =3
All objects in python have an associated truth value. Every object has True value except:
None
False
0 in any numeric type (0,0.0,0+0j etc)
empty sequences (list, tuple, string)
empty mapping types (dictionary, set, etc)
custom classes that implement __bool__ or __len__ method that returns False or 0.
every class in python has truth values defined by a special instance method:
__bool__(self) OR
__len__
When you call bool(x) python will actually execute
x.__bool__()
if instance x does not have this method, then it will execute
x.__len__()
if this does not exist, by default value is True.
For Example for int class we can define bool as below:
def __bool__(self):
return self != 0
for bool(100), 100 !=0 will return True. So
bool(100) == True
you can easily check that bool(0) will be False. with this for instances of int class only 0 will return False.
another example= bool([1,2,3])
[1,2,3] has no __bool__() method defined but it has __len__() and since its length is greater than 0, it will return True. Now you can see why empty lists return False.

Categories