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. -- http://mail.python.org/mailman/listinfo/python-list