Coding style

C

Carl Banks

Bruno said:
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". For lists, it's "empty". For numpy arrays, there is no
truth value.

For the purpose of writing generic functions, this is inconsistent.
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.

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.
And, as I've explained in other posts, this can lead to subtle bugs.
Whereas if you check for emptiness using len, it throws an exception
right away, no bugs. It's safer to use len. (Safest of all is not to
check for emptiness at all.)

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.

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, you'd have to check for emptiness with len. 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.


Carl Banks
 
B

Bruno Desthuilliers

Carl said:
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.





You know very well that not all iterables can know their length ahead
of time.

Yes, but I was talking about *sequences*, not iterables.
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.
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,
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.
 
P

Patrick Maupin

Carl said:
Here's another reason not to use "if lst". Say you have a function
that looks like this:

def process_values(lst):
if not lst:
return
do_expensive_initialization_step()
for item in lst:
do_something_with(item)
do_expensive_finalization_step()

That works, right? No problem, right?

What if you called the function like this:

process_values(x.strip() for x in values_lst)

Oops, now we've just gone through an expensive initialization and
finalization for nothing (since values_lst was empty). Maybe some
subtle bugs introduced. If we're lucky, the finalization step will
throw an exception.

If we had used "if len(list)>0", we'd have gotten a nice exception
telling us that a generator is not welcome. Then we'd have changed the
argument to a list comprehension, or better, changed the function to
work for any iterator.

The argument that one should always use len() to test whether sequences
are empty or not simply because the use of len() gives a free "is it a
sequence?" type-check is not apt to be well received by an audience
which rejects explicit type-checking in general.

The specific example given, where a lack of a len() works correctly,
except for using more execution time on generators than on lists, is
not apt to be well received by an audience which rejects premature
optimizations in general, and which believes that if you don't notice a
speed problem, it doesn't exist, and if you _do_ notice a speed
problem, the profiler is the best tool to attack it with.

The perverse wish, expressed in the specific example, that SOME piece
of code SOMEWHERE should PLEASE throw an exception because some idiot
passed a generator expression rather than a list into a function, is
not apt to be well received by an audience which strives for generality
when it makes sense; and I daresay most members of that audience, if
confronted with the wished-for exception, would fix the function so
that it quite happily accepted generator expressions, rather than
changing a conditional to use len() just so that an equivalent
exception could happen a bit earlier.

I'm not saying that _everybody_ on this list is in any of these
audiences, but I would suspect that all the people arguing with you are
:)

Regards,
Pat
 
D

Daniel Dittmar

Patrick said:
The argument that one should always use len() to test whether sequences
are empty or not simply because the use of len() gives a free "is it a
sequence?" type-check is not apt to be well received by an audience
which rejects explicit type-checking in general.

No explicit type check. More of an implicit behaviour check. OK,
wise guys are not apt to be well received by ... well, any audience.
The perverse wish, expressed in the specific example, that SOME piece
of code SOMEWHERE should PLEASE throw an exception because some idiot
passed a generator expression rather than a list into a function, is
not apt to be well received by an audience which strives for generality
when it makes sense; and I daresay most members of that audience, if
confronted with the wished-for exception, would fix the function so
that it quite happily accepted generator expressions, rather than
changing a conditional to use len() just so that an equivalent
exception could happen a bit earlier.

Premature generalization: the new 'premature optimization'.

Daniel
 
V

Volker Grabsch

Bruno Desthuilliers said:
Carl said:
Bruno Desthuilliers wrote:

I'm well aware of Python's semantics, and it's irrelvant to my
argument. [...]
If the language
were designed differently, then the rules would be different.

Totally true - and totally irrelevant IMHO.

I strongly advise not to treat each others thoughts as irrelevant.
Assuming the opposite is a base of every public dicussion forum.


I assume here is a flaw in Python. To explain this, I'd like to
make Bruno's point clearer. As usually, code tells more then
thousand words (an vice versa :)).

Suppose you have two functions which somehow depend on the emptyness
of a sequence. This is a stupid example, but it demonstrates at
least the two proposed programming styles:

------------------------------------------------------.... if x:
.... print "Non-Empty"
.... else:
.... print "Empty"
.... .... if len(x) > 0:
.... print "Non-Empty"
.... else:
.... print "Empty"
------------------------------------------------------

Bruno pointed out a subtle difference in the behaviour of those
functions:

------------------------------------------------------
a = []
test1(a) Empty
test1(iter(a)) Non-Empty
test2(a) Empty
test2(iter(a))
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in test2
TypeError: len() of unsized object
------------------------------------------------------


While test1() returns a wrong/random result when called with an
iterator, the test2() function breaks when beeing called wrongly.

So if you accidently call test1() with an iterator, the program
will do something unintended, and the source of that bug will be
hard to find. So Bruno is IMHO right in calling that the source
of a suptle bug.

However, if you call test2() with an iterator, the program will
cleanly break early enough with an exception. That is generally
wanted in Python. You can see this all over the language, e.g.
with dictionaries:

------------------------------------------------------
d = { 'one': 1 }
print d['one'] 1
print d['two']
Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'two'
------------------------------------------------------

Python could have been designed to return None when d['two'] has been
called, as some other (bad) programming languages would. This would
mean that the problem will occur later in the program, making it easy
to produce a subtle bug. It would be some effort to figure out the
real cause, i.e. that d had no entry for 'two'.

Luckily, Python throws an exception (KeyError) just at the original
place where the initial mistake occured. If you *want* to get None in
case of a missing key, you'll have to say this explicitly:

------------------------------------------------------None
------------------------------------------------------

So maybe "bool()" should also break with an exception if an object
has neither a __nonzero__ nor a __len__ method, instead of defaulting
to True. Or a more strict variant of bool() called nonempty() should
exist.

Iterators don't have a meaningful Boolean representation, because
phrases like "is zero" or "is empty" don't make sense for them. So
instead of answering "false", an iterator should throw an exception
when beeing asked whether he's empty.

If a function expects an object to have a certain protocol (e.g.
sequence), and the given object doesn't support that protocol,
an exception should be raised. This usually happens automatically
when the function calls a non-existing method, and it plays very
well with duck typing.

test2() behaves that way, but test1() doesn't. The reason is a
sluttery of Python. Python should handle that problem as strict
as it handles a missing key in a dictionary. Unfortunately, it
doesn't.

I don't agree with Bruno that it's more natural to write
if len(a) > 0:
...
instead of
if a:
...

But I think that this is a necessary kludge you need to write
clean code. Otherwise you risk to create subtle bugs. This advise,
however, only applies when your function wants a sequence, because
only in that can expect "len(a)" to work.

I also agree with Carl that "if len(a) > 0" is less universal than
"if a", because the latter also works with container-like objects
that have a concept of emptiness, but not of length.

However, this case is less likely to happen than shooting yourself
in the foot by passing accidently an iterator to the function
without getting an exception. I think, this flaw in Python is deep
enough to justify the "len() > 0" kludge.


IMHO, that flaw of Python should be documented in a PEP as it violates
Python's priciple of beeing explicit. It also harms duck typing.


Greets,

Volker
 
D

Donn Cave

"Carl Banks said:
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.
And, as I've explained in other posts, this can lead to subtle bugs.
Whereas if you check for emptiness using len, it throws an exception
right away, no bugs. It's safer to use len. (Safest of all is not to
check for emptiness at all.)

Yes, it's clearly more direct to catch IndexError, than to
try to anticipate it.

Donn Cave, (e-mail address removed)
 
V

Volker Grabsch

Bruno Desthuilliers said:
FWIW, it's also more generic (you could have an object supporting
pop() but not __len__()), less error-prone,

While I agree with all other points, I don't think that it's less
error-prone. See my other posting where I worked out this a flaw
of Python.


Greets,

Volker
 
D

David M. Cooke

Carl Banks said:
Patrick said:
PTY said:
It looks like there are two crowds, terse and verbose. I thought terse
is perl style and verbose is python style. BTW, lst = [] was not what
I was interested in :) I was asking whether it was better style to
use len() or not.

It's not canonical Python to use len() in this case. From PEP 8:

- For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.

Yes: if not seq:
if seq:

No: if len(seq)
if not len(seq)

The whole reason that a sequence supports testing is exactly for this
scenario. This is not an afterthought -- it's a fundamental design
decision of the language.

That might have made sense when Python and string, list, tuple were the
only sequence types around.

Nowadays, Python has all kinds of spiffy types like numpy arrays,
interators, generators, etc., for which "empty sequence is false" just
doesn't make sense. If Python had been designed with these types in
mind, I'm not sure "empty list is false" would have been part of the
language, let alone recommend practice.

Bruno's already mentioned that iterators and generators aren't
sequences. Numpy arrays act like the other sequence types:
a = numpy.array([])
a array([], dtype=int64)
len(a) 0
bool(a)
False

(0-dimensional numpy arrays are pathological anyways)
 
D

David M. Cooke

[email protected] (David M. Cooke) said:
Bruno's already mentioned that iterators and generators aren't
sequences. Numpy arrays act like the other sequence types:
a = numpy.array([])
a array([], dtype=int64)
len(a) 0
bool(a)
False

(0-dimensional numpy arrays are pathological anyways)

*cough* as a Numpy developer I should know better. Numpy arrays that
have more than one element don't work in a boolean context:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

The reason for this is that it really was a common source of errors,
because of the rich comparision semantics used. If a and b are numpy
arrays, 'a == b' is an array of booleans.

Numpy arrays of one element act like scalars in boolean contexts:
a = numpy.array([0])
bool(a) False
a = numpy.array([1])
bool(a)
True

(this is partly because we define a comphensive hierarchy of scalar
types to match those available in C).
 
B

bearophileHUGS

Volker said:
IMHO, that flaw of Python should be documented in a PEP as it violates
Python's priciple of beeing explicit. It also harms duck typing.

I think this may be good food for Python 3.0, the are removing
undefined comparisons too (>), etc.

bye,
bearophile
 
B

Bruno Desthuilliers

Volker Grabsch a écrit :
Bruno Desthuilliers said:
Carl said:
Bruno Desthuilliers wrote:

I'm well aware of Python's semantics, and it's irrelvant to my
argument.
[...]
If the language
were designed differently, then the rules would be different.

Totally true - and totally irrelevant IMHO.


I strongly advise not to treat each others thoughts as irrelevant.
Assuming the opposite is a base of every public dicussion forum.

"Irrelevant" may not be the best expression of my thought here - it's
just that Carl's assertion is kind of a tautology and doesn't add
anything to the discussion. If Python had been designed as statically
typed (with declarative typing), the rules would be different. Yeah,
great. And now ?
I assume here is a flaw in Python. To explain this, I'd like to
make Bruno's point

Actually Carl's point, not mine.
clearer. As usually, code tells more then
thousand words (an vice versa :)).

Suppose you have two functions which somehow depend on the emptyness
of a sequence. This is a stupid example, but it demonstrates at
least the two proposed programming styles:

------------------------------------------------------

... if x:
... print "Non-Empty"
... else:
... print "Empty"
...

... if len(x) > 0:
... print "Non-Empty"
... else:
... print "Empty"
------------------------------------------------------

Bruno
Carl

pointed out a subtle difference in the behaviour of those
functions:

------------------------------------------------------
a = []
test1(a)
Empty

Non-Empty

Empty
test2(iter(a))

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in test2
TypeError: len() of unsized object
------------------------------------------------------


While test1() returns a wrong/random result when called with an
iterator, the test2() function breaks when beeing called wrongly.

Have you tried these functions with a numpy array ?
So if you accidently call test1() with an iterator, the program
will do something unintended, and the source of that bug will be
hard to find. So Bruno is IMHO right in calling that the source
of a suptle bug.

Actually it's Carl who makes that point - MHO being that it's a
programmer error to call a function with a param of the wrong type.
However, if you call test2() with an iterator, the program will
cleanly break early enough with an exception. That is generally
wanted in Python. You can see this all over the language, e.g.
with dictionaries:

------------------------------------------------------
d = { 'one': 1 }
print d['one']
1
print d['two']

Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'two'
------------------------------------------------------

Python could have been designed to return None when d['two'] has been
called, as some other (bad) programming languages would. This would
mean that the problem will occur later in the program, making it easy
to produce a subtle bug. It would be some effort to figure out the
real cause, i.e. that d had no entry for 'two'.

I don't think the comparison is right. The equivalent situation would be
to have a function trying to access d['two'] on a dict-like type that
would return a default value instead of raising a KeyError.
Luckily, Python throws an exception (KeyError) just at the original
place where the initial mistake occured. If you *want* to get None in
case of a missing key, you'll have to say this explicitly:

------------------------------------------------------


None
------------------------------------------------------

So maybe "bool()" should also break with an exception if an object
has neither a __nonzero__ nor a __len__ method, instead of defaulting
to True.

FWIW, Carl's main example is with numpy arrays, that have *both* methods
- __nonzero__ raising an expression.
Or a more strict variant of bool() called nonempty() should
exist.

Iterators don't have a meaningful Boolean representation,
because
phrases like "is zero" or "is empty" don't make sense for them.

If so, almost no type actually has a "meaningfull" boolean value. I'd
rather say that iterators being unsized, the mere concept of an "empty"
iterator has no meaning.
So
instead of answering "false", an iterator should throw an exception
when beeing asked whether he's empty.


If a function expects an object to have a certain protocol (e.g.
sequence), and the given object doesn't support that protocol,
an exception should be raised.

So you advocate static typing ? Note that numpy arrays actually have
both __len__ and __nonzero__ defined, the second being defined to
forgive boolean coercion...
This usually happens automatically
when the function calls a non-existing method, and it plays very
well with duck typing.

test2() behaves that way, but test1() doesn't. The reason is a
sluttery of Python. Python should handle that problem as strict
as it handles a missing key in a dictionary. Unfortunately, it
doesn't.

Then proceed to write a PEP proposing that evaluating the truth value of
an iterator would raise a TypeError. Just like numpy arrays do - as a
decision of it's authors.
I don't agree with Bruno
s/bruno/Carl/

that it's more natural to write
if len(a) > 0:
...
instead of
if a:
...

But I think that this is a necessary kludge you need to write
clean code. Otherwise you risk to create subtle bugs.

s/you risk to create/careless programmers will have to face/

And FWIW, this is clearly not the opinion of numpy authors, who state
that having len > 0 doesn't means the array is "not empty"...
This advise,
however, only applies when your function wants a sequence, because
only in that can expect "len(a)" to work.

Since sequence types are defined as having a False value when empty,
this test is redondant *and* "will create subtle bugs" when applied to a
numpy array.
I also agree with Carl that "if len(a) > 0" is less universal than
"if a", because the latter also works with container-like objects
that have a concept of emptiness,

s/emptiness/boolean value/
but not of length.
However, this case is less likely to happen than shooting yourself
in the foot by passing accidently an iterator to the function
without getting an exception. I think, this flaw in Python is deep
enough to justify the "len() > 0" kludge.

It surely justify some thinking on the boolean value of iterators. Since
the common idiom for testing non-None objects is an explicit identity
test against None - which makes sens since empty sequences and zero
numerics eval to False in a boolean context - the less inappropriate
solution would be to have iterators implementing __nonzero__ like numpy
arrays do.
IMHO, that flaw of Python should be documented in a PEP as it violates
Python's priciple of beeing explicit.

Here again, while I agree that there's room for improvement, I don't
agree on this behaviour being a "flaw" - "minor wart" would better
describe the situation IMHO.
 
B

Bruno Desthuilliers

Volker Grabsch a écrit :
While I agree with all other points, I don't think that it's less
error-prone.

There are less risk of a typo with "if a:" than with "if len(a) > 0".
See my other posting where I worked out this a flaw
of Python.

See my answer where I don't agree on this being a "flaw" - a "minor
wart" at most !-)
 
C

Carl Banks

Bruno said:
"Irrelevant" may not be the best expression of my thought here - it's
just that Carl's assertion is kind of a tautology and doesn't add
anything to the discussion. If Python had been designed as statically
typed (with declarative typing), the rules would be different. Yeah,
great. And now ?

I was answering someone who said you should use "if lst" because PEP 8
says to. I proposed that the PEP might be outdated here, and gave
reasons why I think it would be different if it were written today. (I
also, regrettably, implied the language might have been designed
differently.) This all might be irrelevant to you, but it's relevant
to the original question of whether that clause of PEP 8 is outdated.
I think it is.

BTW, I'm still waiting for anyone to come up with a real benefit of the
"if lst" test. I have yet to see a good reason than non-answer
cop-outs "it's Pythonic", "it's stood the test of time", and "it's in
PEP 8". "It's standard idiom" is about the best I've seen, and that's
pretty weak. "Saving a few keystrokes" is, as always, not a good
reason.


Carl Banks
 
C

Carl Banks

Bruno said:
There are less risk of a typo with "if a:" than with "if len(a) > 0".

So, it's more important to protect against typos than subtle bugs?


Carl Banks
 
B

Bruno Desthuilliers

Carl Banks a écrit :
So, it's more important to protect against typos than subtle bugs?

People making smart points are really annoying... !-)

wrt/ to the "subtle bug" point, MHO is that a better solution could be
to have iterators/generators implement __nonzero__ the same way numpy
arrays do. It may not be a very strong argument, but I actually like the
fact that empty sequences eval to false just like numeric zeros and None...
 
C

Carl Banks

Bruno said:
Carl Banks a écrit :

People making smart points are really annoying... !-)

wrt/ to the "subtle bug" point, MHO is that a better solution could be
to have iterators/generators implement __nonzero__ the same way numpy
arrays do. It may not be a very strong argument, but I actually like the
fact that empty sequences eval to false just like numeric zeros and None....

Well, I certainly can agree with that, except for the last point. :) I
certainly wouldn't want to keep that unfortunate behavior around just I
have something to use as an argument using len to test emptiness.


Carl Banks
 
J

Jorge Godoy

Carl Banks said:
Well, I certainly can agree with that, except for the last point. :) I
certainly wouldn't want to keep that unfortunate behavior around just I
have something to use as an argument using len to test emptiness.

On the other hand, having this behavior makes it so simple to deal with some
algorithms because on doesn't need to know if the given object does or does
not support len()...

Having to test if something is of certain type then choosing what kind of test
to apply is not something I'd like to have to do all the time.
 
T

Terry Reedy

The perverse wish, expressed in the specific example, that SOME piece
of code SOMEWHERE should PLEASE throw an exception because some idiot
passed a generator expression rather than a list into a function, is
not apt to be well received by an audience which strives for generality
when it makes sense; and I daresay most members of that audience, if
confronted with the wished-for exception, would fix the function so
that it quite happily accepted generator expressions, rather than
changing a conditional to use len() just so that an equivalent
exception could happen a bit earlier.

Given that the input is going to be scanned by an iterator, it really makes
sense to me to accept an iterator as input. (Unless the function is for
special-case usage in a predefined, never to be expanded, set of
circumstances in which such generality is not needed. In such a case, if
lst: is no problem.) I think the following, untested rewrite suffices.

def process_values(lst):
it = iter(lst)
try:
item = it.next()
do_expensive_initialization_step()
do_something_with(item) # see note
for item in it:
do_something_with(item)
do_expensive_finalization_step()
except StopIteration:
pass # or any special empty input code

# note: if writing do_something_with(item) is bothersome,
# replace 3 lines with
while True:
do_something_with(item)
try:
item = it.next
except StopIteration:
break

In general, to work with iterators instead of containers, change

if container:
do_stuff()
else:
do_empty()

to

try:
item = it.next()
do_modified_stuff() # taking into account that have item already
except StopIteration:
do_empty()

Guido has so far vetoed adding .__len__() to the iterator protocol because
a) it is not always possible and b) he want to keep the protocol as simple
as it is.

Terry Jan Reedy
 
C

Carl Banks

Jorge said:
On the other hand, having this behavior makes it so simple to deal with some
algorithms because on doesn't need to know if the given object does or does
not support len()...

First of all, the unfortunate behavior I was referring to was the fact
that iterables that have unknown length are true in a boolean context,
even if they happen to be empty. Bruno and I had a disagreement over
whether this should also be a wart for lists and such, but I think we
agree that it would be better generators and other iterators raised an
exception in a boolean context.

Getting back to your reply--can you give an example of a useful
function that needs to do what you want? (Let's disregard iterators
and arrays for now, and focus on older Python types like lists, tuples,
strings, integers, floats, None, etc.) Can you give me an example of a
useful function that needs to test the truth value of an object, but
that can't rely on it having a length?

The only example I can think of here is a function that does nothing
with an object except pass it to other functions. Almost anything else
you do with an object pigeonholes it as a sequence or atomic type:
you've already assumed whether it has a length or not.


Carl Banks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top