Do you think there should be different results for bool("no"), bool("false"), bool("heckno!"), bool("heckyes!")?
Edit: should have included internationalization: bool("nein!")
Do you think there should be different results for bool("no"), bool("false"), bool("heckno!"), bool("heckyes!")?
Edit: should have included internationalization: bool("nein!")
But it's entirely reasonable to think it would. I honestly don't understand why it wouldn't, because:
>>> int("35")
35
>>> float("3.5")
3.5
>>> bool("False")
True
If casting from a string to a type works with ints and floats, why not with bools? What possible justification is there?And of course it doesn't need to work for "no" or "heckno!", that's silly. But it sure seems like it ought to work on whatever the official string representation is. And not produce:
>>> bool(str(False))
True
I'd honestly much prefer bool() threw an exception on receiving a string, rather than act the way it does now. prefer bool() threw an exception on receiving a string, rather than act the way it does now.
That breaks the truthiness cornerstone of the language. You can write a = 1 # or [], (), "yo", "false", 3.2, MyFooClass(), (1,), False
if a:
fire_ze_missles()
else:
declare_peace()
Upon encountering `a`, Python is evaluating bool(a). If that no longer works for strings, you now need a separate code path for determining a non-empty string.It can short-circuit the brain upon reading a word that you know means false, but the Python rules are consistent. "Empty" is False, everything else is True.
> I'd honestly much prefer bool() threw an exception on receiving a string, rather than act the way it does now.
They serve fundamentally different purposes. bool() is a truthiness check and not a type cast like int() and float(). It seems like a lot of people take issue with the name, because it was called something like istruthy() the discussion about it wouldn't be happening.
Right, the bug is in the inconsistent naming.
It's roughly as bad as having arithmetic operators named +, -, *, / that perform arithmetic as usually understood, except that + actually performs XOR and is documented to do so.
The comment I responded to didn't seem to realize that because they asked why it behaves the way it does, so I explained.
There's no type casting in Python. int(), float() and bool() just create objects of their respective types, passing the arguments to the initializer. They are not fundamentally different from, say, PostgresqlDriver() in this regard.
Different classes will provide different ways to construct objects depending on what is most useful. For int and float, the most useful thing to do when receiving a string is to parse it; for bool, the most useful thing to do is to check its truthiness; for PostgresqlDriver, the most useful thing to do is to interpret it as a database URL and connect to it.
If you search "type casting in Python" you will find lots of articles explaining how to use int(), str(), etc. to cast. This is a common and well-documented concept, even if it's different under the hood from e.g. C.
The idea that you'd name a function bool() and have it act differently is a deeply confusing design decision that it's understandable people would get misled by and frustrated with. This is a function named after a fundamental type. It's not a random user-defined constructor.
if "False":
# What do you expect? True or False?
print("True")
else:
print("False")
bool() is consistent with how "truthiness" happens in python. Otherwise we end up with the YAML norway problem. if bool("False"):
print("True")
else:
print("False") # This would be different if we landed here.
And that would be different behavior then the above -- creating a nasty inconsistency.Honestly it's not that hard to write something that looks like this:
def str_to_bool(val: str) -> bool:
return val.lower() in ["yes", "true", "1"]https://docs.python.org/3/library/functions.html#bool
A good tutorial will reflect this fact and use appropriate language.
Both the idea that you can "cast", and the idea that bool is a function, are misunderstandings rooted in the idea that Python should be like C in all ways.
int() and float() behave like type casting, bool() does not. It's a truthiness check that would be more aptly named istruthy(). In python non-empty strings are truthy, so providing any string except for "" to bool() will return True, including "False".
(char*)21 != "21"
Casting is converting the container, the interpretation.What you're reaching for is type conversion. Some languages have "implicit conversion" when casting, but the word itself doesn't require it.
A cast of insert a conversion that wouldn't take place:
1/2 vs 1/(double)2
or coerce a conversion that otherwise requires a diagnostic: bar *b = 0;
foo *f = (foo *) b;
Loosely speaking, casting is another name for coercion, which refers to making a conversion happen that might not otherwise.Because I'm tired, and this is a very basic topic, I'm afraid I'm just going to rip from Wikipedia:
> In most ALGOL-like languages, such as Pascal, Modula-2, Ada and Delphi, conversion and casting are distinctly different concepts. In these languages, conversion refers to either implicitly or explicitly changing a value from one data type storage format to another, e.g. a 16-bit integer to a 32-bit integer. The storage needs may change as a result of the conversion, including a possible loss of precision or truncation. The word cast, on the other hand, refers to explicitly changing the interpretation of the bit pattern representing a value from one type to another. For example, 32 contiguous bits may be treated as an array of 32 Booleans, a 4-byte string, an unsigned 32-bit integer or an IEEE single precision floating point value. Because the stored bits are never changed, the programmer must know low level details such as representation format, byte order, and alignment needs, to meaningfully cast.
> In the C family of languages and ALGOL 68, the word cast typically refers to an explicit type conversion (as opposed to an implicit conversion), causing some ambiguity about whether this is a re-interpretation of a bit-pattern or a real data representation conversion. More important is the multitude of ways and rules that apply to what data type (or class) is located by a pointer and how a pointer may be adjusted by the compiler in cases like object (class) inheritance.
Implicit conversion can be seen as the compiler deciding among several possible conversions (or possibly just one) and inserting the coercion/casting operator into the intermediate code to make it happen.
(Of course, this can be a run-time decision based on dynamic types also, but the reasoning is the same. E.g. the run-time sees that a plus operation is adding an integer and float, and can either signal an error (requiring the program to be repaired by inserting a conversion operation into the expression), or just do that conversion, like the integer operand to float.
Otherwise types are just sugar. Indicies are just sugar. Lists are just sugar.
That said, I think you're correct about the casting versus conversion distinction. Languages frequently overload established terminology with slightly modified variants and it's incredibly confusing.
`bool` would have no value if it threw an error in this case because if strings can't be passed to it, then no other type would sensibly work either. It would basically just become `bool(False) -> False` and `bool(True) -> True`.
It's pretty standard to convert integers to bools, where 0 becomes False and everything else becomes True. That is absolutely sensible and useful current behavior.
Not consistent at all.
There's nothing consistent about bool(str(False)) == True.
It's standard in computing for zero integers to represent False. Heck, bool is a subclass of int. Extending that to the length of strings is where things start to go off the rails in terms of consistency... and why you would ever even want that is beyond me.
Which becomes a different issue - what do you think str(True) and str(False) should produce. Integer representations? That then makes other things unintuitive with changing the form of a boolean.
print(0, 1, False, True)
# today: 0 1 False True
# as ints: 0 1 0 1
# new str: 0 1 "True" ""str(False) == 'False' is entirely logical.
So therefore bool('False') == False would be consistent.
And bool('foo') would produce an exception the exact same way int('foo') and float('foo') already do.
Who on earth thought it was a good idea that 'foo' could or should be interpreted as a boolean...?? The entire concept of 'truthiness' outside of ints is unhelpful. It's just asking for bugs. That the length of a string, rather than its content, should determine a boolean value is one of the more bizarre things I've come across in programming languages. Use len() if you want that. It's only 5 extra characters.