Coding style

Bruno Desthuilliers onurb at xiludom.gro
Tue Jul 18 11:04:46 EDT 2006


Carl Banks wrote:
> Bruno Desthuilliers wrote:
> 
>>Carl Banks wrote:
>>
>>>Iterables, lists, arrays, and whatever else have overlapping uses, but
>>>bool(obj) behaves differently for different types,
>>
>>bool(obj) will mainly look for __len__(), then for __nonzero__(), then
>>return True. You can only call len(obj) on objects implementing
>>__len__(), so relying on (implicit) 'bool(obj)' is clearly more generic
>>than 'len(obj) > 0'.  Also, since bool(obj) will try to call
>>obj.__len__(), explicitely calling len(obj) doesn't make any difference.
> 
> 
> I'm well aware of Python's semantics, and it's irrelvant to my
> argument.  What low level operations it does do not concern me.  I'm
> concerned about what equats to "truth".  For generators and such, it's
> "always". 

"generators and such" are not sequences.

> For lists, it's "empty".  For numpy arrays, there is no
> truth value.

Then treat numpy arrays as iterables (which they are), not as sequences.

> For the purpose of writing generic functions, this is inconsistent.

Not if you choose to design your function to work on iterables (which
means you don't use len() at all to test for emptiness).

> And, IMO, it's possible that the language would have been designed
> differently (by not letting them have any truth value) if they'd been
> around in the beginning.
> 
> 
> 
>>And if you want your own sequence types to be well-behaved sequence
>>types, just take time to implement the needed protocol(s), including
>>__len__().
> 
> 
> You know very well that not all iterables can know their length ahead
> of time.

Yes, but I was talking about *sequences*, not iterables.

> 
>>For short: either your function expects an iterable or it expects a
>>sequence. If it expects an iterable, treat it as an iterable wether it
>>happens to be a sequence or not.
> 
> 
> 1. This is fine in a perfect world where all code clearly conforms to
> expectation.  Problem is, a lot doesn't.  I think it's quite easy to
> accidentally check something intended as an iterable for emptiness.

Testing a random iterable for emptiness can not be done by testing it's
length.

> And, as I've explained in other posts, this can lead to subtle bugs.

If you clearly documents what your function expects (ie sequence or
iterable), then I don't see any subtleties involved...

> Whereas if you check for emptiness using len, it throws an exception
> right away, no bugs.  It's safer to use len.

It's safer to decide which protocol is expected, ie iterable or
sequence, and then write the code according to this expectation.

>  (Safest of all is not to
> check for emptiness at all.)

Unless you clearly expect a sequence and have to branch according to
it's state (ie empty/not empty).

> 2. This logic doesn't work for numpy arrays.  In a lot of cases, a
> function expecting a list works perfectly fine if you pass it a numpy
> arrray.  But, if you were to write such a function with "if lst"
> instead of "if len(lst)>0", it's guaranteed to fail.  The function is
> more generic with the len test.

If the function is to work with non-sequence types, write it so it can
work with non-sequence types.

>>>it's possible that these types wouldn't even have a boolean
>>>value and any tests for emptiness would have to be explicit.
>>
>>Yes ? How ? Calling len() on them ?-)
>>(hint: reread how len() and bool() works wrt/ __len__())
> 
> 
> Yes.  If the language had been designed such that a list had no
> nb_nonzero slot,

>>> [].__nonzero__
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'list' object has no attribute '__nonzero__'


> you'd have to check for emptiness with len.

bool(obj) *do* the test on __len__() if __nonzero__() is not implemented.

>  Perhaps
> you're missing some of the nuances of English verb tenses (don't feel
> too bad, it's hard).  I'm not arguing "what is", I'm arguing what
> "could have been if circumstances were different".  If the language
> were designed differently, then the rules would be different.

Totally true - and totally irrelevant IMHO.

-- 
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb at xiludom.gro'.split('@')])"



More information about the Python-list mailing list