From: Steven D'Aprano on
On Mon, 12 Jul 2010 19:28:28 -0600, Ian Kelly wrote:

> On Mon, Jul 12, 2010 at 6:18 PM, Steven D'Aprano
> <steve(a)remove-this-cybersource.com.au> wrote:
>>> I prefere to explicitly write what I want to test:
>>>
>>> if myInt <> 0:
>>
>> I would argue against that. Why do you, the coder, care about the
>> specific details of treating ints in a boolean context? The int type
>> itself knows, leave the decision to it.
>
> I think you're missing the point. He's not using ints in a boolean
> context. If it were a boolean context, he would be using bools in the
> first place.

Of course he is -- he's branching on an int (a boolean context), and
explicitly writing out the test as myInt <> 0. In fact, that test could
just as easily be written as bool(myInt), which has the benefit of being
even more explicit that you want a bool.

It's also silly. Explicitness is not always a virtue. Beginners sometimes
write things like:

s = "hello "
t = "world"
print str(s + t)

and we rightly shake our heads at the sheer n00b-ness of it. Writing the
explicit tests:

if bool(myInt):

or even:

if myInt <> 0:

are firmly in the same category. The only difference is that it is more
familiar and therefore comfortable to those who are used to languages
that don't have Python's truth-testing rules.



> What he is objecting to is the practice of testing for
> special cases of ints (i.e. 0) by treating them as bools. The specific
> details of converting ints to bools are very much relevant here; as long
> as 0 is false, it works. If -1 is false (a semantic I have actually
> seen used), then it does not.

You've seen -1 being used as false? Where? Are you still talking about
Python builtins or language semantics?

If you're about to say string.find(substring), no, absolutely not. find
does not return a true/false flag, it returns an index, with -1 the
sentinel for Not Found. This is not a flag!

In fact, one of the motivations for adding bools to Python was to avoid
people mistakenly thinking that cmp(a, b) returned a flag 0, 1 when it
actually returns a three-state -1, 0, 1. This was a common source of
errors before Python got bools.


--
Steven
From: Paul Rubin on
Steven D'Aprano <steve-REMOVE-THIS(a)cybersource.com.au> writes:
> Writing the explicit tests:
> if bool(myInt):
> or even:
> if myInt <> 0:
>
> are firmly in the same category. The only difference is that it is more
> familiar and therefore comfortable to those who are used to languages
> that don't have Python's truth-testing rules.

It's like list.append returning None. It helps catch errors.
From: Steven D'Aprano on
On Mon, 12 Jul 2010 17:36:38 -0700, Paul Rubin wrote:

>> I would argue against that. Why do you, the coder, care about the
>> specific details of treating ints in a boolean context? The int type
>> itself knows, leave the decision to it.
>
> There is a horrible (IMO) thing that Perl, Lua, and Javascript all do,
> which is automatically convert strings to numbers, so "12"+3 = 15.
> Python has the good sense to throw a type error if you attempt such an
> addition, but it goes and converts various types to bool automatically,

No, what Python does is more subtle than that. An example using strings
will (I hope!) make it clear. Or possibly muddy the waters even more.

Compare converting strings to ints: the string "1" maps to the int 1, "2"
to 2, and so forth. There's a one-to-one map of string to int (modulo
unicode and whitespace issues), and since this is more or less a
universal standard, it's enshrined in the language.

Now consider converting strings to bools. Should "true" map to True? Or
"yes", "ja", "vrai", "waar", or something else? That's an application-
specific question, not a universal standard (not even a de facto
standard), and Python rightly avoids it.

What about "maybe" or "strawberry jam"? You can't convert "strawberry
jam" into True or False any more than you can convert it into an int.

What Python does instead is to accept *any* object in a context where
other languages (such as Pascal) would insist on a boolean. In practice,
that means branches (if) as well as the short-cut operators and, or, not.
The semantics of this is well-defined, and I trust I don't need to go
over it again.

In an expression like:

x and y

unlike Pascal, there is no requirement that x and y be booleans. This is
why I talk about x and y being used "in a boolean context", rather than
converting it to a bool. [3,4,5] is not, by any stretch of the
imagination, True converted into a list, and likewise [2,3,4] is a list
and can't be converted to a flag any more than it can be converted to an
int. But what I do say is that, according to Python's semantics, the list
[3,4,5] is equivalent to True in a boolean context.

Where Python muddies the water is to provide a bool() built-in which
*does* convert any object to canonical boolean form. bool([2,3,4])
returns True, which contradicts what I said above about not converting
the list into a flag. I accept this -- it's a triumph of practicality
over purity. It would be silly to force people to write:

# get the canonical form
if any_old_object:
flag = True
else:
flag = False

when we can say flag = bool(any_old_object).

One last thing -- we can see that Python does *not* convert objects to
bools "in a boolean context". The Python virtual machine really does
accept any object as an argument to and/or/not operators, as well as if:

>>> import dis
>>> dis.dis(compile('a or b', '', 'single'))
1 0 LOAD_NAME 0 (a)
3 JUMP_IF_TRUE 4 (to 10)
6 POP_TOP
7 LOAD_NAME 1 (b)
>> 10 PRINT_EXPR
11 LOAD_CONST 0 (None)
14 RETURN_VALUE


The JUMP_IF_TRUE opcode accepts any object, not just True or False.



--
Steven
From: Ian Kelly on
On Mon, Jul 12, 2010 at 9:16 PM, Steven D'Aprano
<steve-REMOVE-THIS(a)cybersource.com.au> wrote:
> You've seen -1 being used as false? Where? Are you still talking about
> Python builtins or language semantics?

Some of our database tables at work use 1 for true, -1 for false, and
0 for neither. Don't look at me, I didn't design it. Why they didn't
just make the column nullable is beyond me, but that's the way it is.
From: Steven D'Aprano on
On Mon, 12 Jul 2010 20:22:39 -0700, Paul Rubin wrote:

> Steven D'Aprano <steve-REMOVE-THIS(a)cybersource.com.au> writes:
>> Writing the explicit tests:
>> if bool(myInt):
>> or even:
>> if myInt <> 0:
>>
>> are firmly in the same category. The only difference is that it is more
>> familiar and therefore comfortable to those who are used to languages
>> that don't have Python's truth-testing rules.
>
> It's like list.append returning None. It helps catch errors.

How?

>>> myInt = 'x'
>>> if myInt <> 0:
.... print "myInt is not zero, safe to divide"
.... print 42/myInt
....
myInt is not zero, safe to divide
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: unsupported operand type(s) for /: 'int' and 'str'



What error did this catch?


--
Steven