But if you are going to argue that "if obj" is *explicit enough*, then
apply your argument consistently to "String"+1.75 also. Why must we be
explicit about string conversion BUT not boolean conversion?
The problem with "String" + 1.75 is not lack of explicitness, but
ambiguity. The + is operator is plenty explicit, but it is ambiguous when
the operands have different types. Should it...?
- truncate "String" at the first non-digit (hence "") and then coerce
it to 0.0, and hence return the float 1.75?
- coerce "String" to a float NaN on the basis that "String" is
not a number, and hence return NaN?
- coerce 1.75 to a string, and hence return "String1.75"?
The first behaviour is rather dubious, but a good case could be made for
the second or third. Python takes a fourth approach, and refuses to allow
such mixed type operations.
If + always meant "numeric addition", and & was used for string
concatenation, then we could have unambiguous expressions using mixed
types:
1 + 1.75 # int + float always coerces to float
1 + "2" # int + str always coerces to int
1 & "2" # int & str always coerces to str
but since & is used for integer bitwise-and, and + is used for both
concatenation and addition, we can't, and so Python raises an exception.
For arithmetic, there is an unambiguous hierarchy of types, the numeric
tower, which tells us which types coerce to what, e.g.:
int -> float -> complex
But there is no such hierarchy when it comes to (say) mixed strings and
lists, etc., and hence Python raises an exception rather than guessing
which type you wanted as the result.
This is completely irrelevant when it comes to bools -- we don't have to
coerce a value into another type, we just need to know if it is something
or nothing. The object itself is best able to make that decision, hence
delegating it to a protocol and method:
- If the object is a container, and it has a length of 0, it is empty
and hence nothing (falsey); if it has a non-zero length, it is non-empty
and hence something (truthy).
- Otherwise ask the container whether it is something or nothing by
calling __nonzero__ (the original name) or __bool__.
Python makes a rather big blunder, at least from the perspective of
consistency. Bools are ints:
py> issubclass(bool, int)
True
py> isinstance(True, int)
True
py> isinstance(False, int)
True
but there are things that can be converted into bools that can't be
converted into ints, even though bools *are* ints! Contradiction.
py> x = [None, 42, '']
py> bool(x)
True
py> int(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: int() argument must be a string or a number, not 'list'
Since x can be converted into True, and True == 1, you should be able to
convert x into 1. But that's crazy, since x = [None, 42, ''].
*shrug* I don't call this a gotcha, but it is one of the more ugly
consequences of Python's bool implementation.
Can you
reduce this to the absurd? Or will you just choose to ignore this valid
point?
Mu. (Neither true nor false.)