question about True values
Steven D'Aprano
steve at REMOVE.THIS.cybersource.com.au
Sat Oct 28 18:10:59 EDT 2006
On Sat, 28 Oct 2006 03:24:50 -0700, Carl Banks wrote:
> Not all objects that have a state of emptiness consider emptiness to be
> false.
In which case they should define __nonzero__ appropriately.
In which case, calling code that assumes that len(obj) is a substitute for
truth-testing will do the wrong thing.
>> > Whether you test with "if a:" or "if len(a)>0", some objects are
>> > going to be denied.
>>
>> If a class doesn't define __nonzero__ or __len__, it should.
>
> No, it often shouldn't.
Okay, I want to qualify my statement: if a class doesn't define
__nonzero__ or __len__, *and doesn't want the default Python behaviour of
all instances evaluating as True*, then they should.
> A. It's not always desirable for empty to be false. Numpy defines a
> bunch of numeric array types that raise an exception when __nonzero__
> (actually nb_nonzero in the C API) is called. This is the correct
> behavior for numpy. It makes no sense for numpy arrays to be used in a
> boolean context, but they certainly can be empty.
And, appropriate to the class, numpy arrays raise an exception when
__nonzero__ is called -- just as they should.
> B. Sometimes it's impossible to determine the state of emptiness. For
> example, iterators.
Since Guido has ruled that the protocol is that all iterators are True,
there is no need for __nonzero__ since the default behaviour does the job.
[snip]
>> Perhaps this behaviour has changed in version 2.5, if so, I'd like to
>> hear the rationalisation before I declare it a mistake.
>
> You haven't been paying attention.
>
> Yes, this behavior has been changed in 2.5. The built-in iterators
> always return True in 2.5. But even in 2.4, it was not true for
> iterators in general:
Yes, you are right. I was fooled by a coincidence.
> At no point could you count on an iterator returning False for empty,
> unless you'd made it yourself. Neither "if a:" nor "if len(a)>0" is a
> valid test for an empty iterator.
Correct. Guido's decision is that iterators are always "Something" (that
is, True in a truth context) even if they are exhausted.
>> > P.S. binary trees do have length: it's the number of nodes, just as
>> > the number of keys is the length of a dict.
>>
>> I don't know what you were taught, but I was taught that binary trees
>> have height and breadth.
>
> It doesn't really matter. dicts and sets don't have a length, either.
> Or if they do, it's the length of the hash table, not the number of
> entries. Weren't you taught that? But Python uses len() to get the
> number of items in a container. Any Pythonic implementation of a binary
> tree class would use len() to return the number of entries in it.
> Anything that uses indexing ought to define len(), if it can.
In the binary tree:
tree --> A
A.left --> B, A.right --> C
what's tree[0]? Should it be A (preorder), or B (inorder) or C (postorder)?
> Overall, your objections don't really apply, since you're arguing what
> ought to be whereas my argument is pragmatic. Practically speaking, in
> realistic situations, "if len(a)>0" will work for a wider range of types
> than "if a:".
Well, that's a quantitative claim you're making there. Have you
actually gone through, say, the built in types and checked how many
have a length versus how many work in a truth-context?
>>> import types
>>> if types:
... print "Modules work with bool"
...
Modules work with bool
>>> if len(types)>0:
... print "Modules work with len"
...
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: len() of unsized object
"if len(a)>0:" only works for objects that define __len__.
"if a:" works for any object that doesn't go to the trouble of
specifically prohibiting it, as numpy arrays deliberately do. That's the
Python way, and it is a deliberate design.
--
Steven.
More information about the Python-list
mailing list