0

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
halfer
  • 19,824
  • 17
  • 99
  • 186
joel
  • 6,359
  • 2
  • 30
  • 55
  • 3
    You can't print it if it isn't a string. By the way, `print` automatically converts items to their string representation by calling the `__str__` method, which is also what an str call delegates to. – cs95 Jul 22 '18 at 00:51
  • I'm a bit confused as to what the `list(bool())` is supposed to represent. The list constructor explicitly states it takes an iterable, which `bool()` is not. It doesn't seem related to the other examples. – user3483203 Jul 22 '18 at 00:51
  • Why would `str(not True)` not work? `not True` is `False`, and converting that to a printable string results in `False`. It's nothing different than `str(1+1)` yielding `2` and not `1+1`. – Jongware Jul 22 '18 at 00:52
  • `print(str(not True))` works the same way as `print(2 * 4)`: the expression is evaluated, then `str(result)` is printed – Reblochon Masque Jul 22 '18 at 00:54
  • 1
    You can do `str(True)` because `True` has a [`__str__` method](https://docs.python.org/3/reference/datamodel.html#object.__str__). `bool(str(False))` is `True` because non-empty strings are [truthy](https://stackoverflow.com/questions/39983695/what-is-truthy-and-falsy-in-python-how-is-it-different-from-true-and-false/39984051#39984051) – Patrick Haugh Jul 22 '18 at 00:55
  • Regarding your `bool(str(...))` example, typecasts were never intended to be bijections. Consider `float(int(3.5))`. – Silvio Mayolo Jul 22 '18 at 01:57

4 Answers4

8

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.

Community
  • 1
  • 1
Schwern
  • 153,029
  • 25
  • 195
  • 336
  • On round-tripping: I was searching for another example that would make it obvious, but `float(str(-0.0))` yields ... `-0.0`. So much for that. – Jongware Jul 22 '18 at 00:58
  • i get the round trip thing, e.g. `int(bool(5))` is 1. `bool` maps to two values so it can't be round-trip – joel Jul 22 '18 at 01:00
  • 1
    `bool` is not casting, read what it's supposed to do: https://docs.python.org/3/library/functions.html#bool – Daniel Möller Jul 22 '18 at 01:01
  • 1
    @usr2564301 `list(str([1,2]))` is `['[', '1', ',', ' ', ']']`. `bytes(str(b'abc'))` is an exception. Plenty of things don't round-trip. – abarnert Jul 22 '18 at 01:01
  • @usr2564301 `int(float(1.2))` – Schwern Jul 22 '18 at 01:02
  • 1
    @Schwern `"True"` and `"False"` are both f̶a̶l̶s̶e̶ **true**. (Edit submitted) – axolotl Jul 22 '18 at 01:45
3

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.

Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
1

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

Daniel Möller
  • 84,878
  • 18
  • 192
  • 214
  • 1
    "About the bool() function, it's supposed to return True for anything that is not empty or undefined or False." is wrong. First, you can't call it on something undefined (doing anything with something undefined is an exception). Second, the rule is that it returns true for anything that is not empty, false, _or `None`, or zero_. – abarnert Jul 22 '18 at 00:59
-1

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.

dawg
  • 98,345
  • 23
  • 131
  • 206