empty lists vs empty generators

Bengt Richter bokr at oz.net
Mon May 2 21:49:54 EDT 2005


On 2 May 2005 16:14:57 -0700, brian at mirror.org (Brian Roberts) wrote:

>I'm using using generators and iterators more and more intead of
>passing lists around, and prefer them.  However, I'm not clear on the
>best way to detect an empty generator (one that will return no items)
>when some sort of special case handling is required.
>
>Typical code for handling an empty list:
>    if somelist:
>        for x in somelist: 
>            something(x)
>    else:
>        empty_list_special_case
>
>But this doesn't work with iterators -- a generator is "true"
>regardless of whether its going to return any items.  (I understand
>why).
>
>The closest equivalent I know of is:
>    n = 0
>    for n, x in enumerate(somegenerator()):
>       something(x)
>    if n == 0:
>       empty_list_special_case
>
>Which seems rather awkward -- doesn't read as easily for me, and
>introduces another variable.
And, if I understood the intent, doesn't work ;-)

 >>> n = 0
 >>> for n, x in enumerate(c for c in 'a'):
 ...     print 'something', x
 ...
 something a
 >>> if n == 0:
 ...     print 'empty list special case ??'
 ...
 empty list special case ??

You could have used n = -1 as a sentinel that enumerate would not set,
but using a guaranteed-unique sentinel, you don't need enumerate, e.g.,

 >>> x = sentinel = object()
 >>> for x in (c for c in 'a'):
 ...     print 'something', x
 ...
 something a
 >>> if x is sentinel:
 ...     print 'empty list special case ??'
 ...

(nothing printed there)
and for the actually empty sequence

 >>> x = sentinel = object()
 >>> for x in (c for c in ''):
 ...     print 'something', x
 ...
 >>> if x is sentinel:
 ...     print 'empty list special case ??'
 ...
 empty list special case ??

>
>Q1: Is there a better or alternate way to handle this?
>Q2: Is there a way that handles both lists and generators, so I don't
>have to worry about which one I've got?
>
UIAM this should work for any iterable. You don't have to manufacture
a locally bound sentinel as above. You could pick anything to preset
the for-target that you know is not going to be produced by the iterable,
though you might need to use '==' instead of 'is' depending on your choice.
But e.g., I don't think I'd write

    x = Exception  # weird sentinel choice
    for x in mystring:
       print x, ord(x)
    if x is Exception:
       print 'null sequence'

None probably works well a lot of the time, but not always.
Similarly ''. Seems like a builtin sentinel binding like sentinel = object()
might be handy to standardize usage.

Regards,
Bengt Richter



More information about the Python-list mailing list