473,950 Members | 23,241 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

empty lists vs empty generators

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_spec ial_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(someg enerator()):
something(x)
if n == 0:
empty_list_spec ial_case

Which seems rather awkward -- doesn't read as easily for me, and
introduces another variable.

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?

Thanks,
Brian.
Jul 19 '05 #1
10 8056
jfj
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.

Usually it will be the job of the generator to signal something like
this. I think a possible way might be:

class GeneratorEmpty: pass

def generator():
if not X:
raise GeneratorEmpty
for i in X:
yield i

try:
for x in generator
something (x)
except GeneratorEmpty:
generator_speci al_case

The trick is that when generators raise exceptions they terminate.
Although this is probably not what you want. The thing is that you
cannot know if a generator will return any elements until you call
its next() method.

Q2: Is there a way that handles both lists and generators, so I don't
have to worry about which one I've got?


I don't think this is possible. A generator must be called (with
next()) in order for its code to take over and see if it is empty or
not. Unlike the list.
jfj

Jul 19 '05 #2
In article <50************ *************@p osting.google.c om>,
br***@mirror.or g (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.


The best I can come up with is to depend on the fact that

for item in foo:
pass

only defines item if foo yields any items. Assuming item is not defined
before you execute the for loop, you can check to see if it's defined after
the loop, and use that to tell if foo was an empty list or generator.
Here's a demo. Unfortunately, I'm not sure if it's really any cleaner than
your way (but at least it doesn't add any extraneous variables)
# Creates an iterator which yields n items.
class gen:
def __init__(self, n):
self.n = n

def __iter__(self):
for i in range(self.n):
yield None

def checkEmpty(genO rList):
for item in genOrList:
pass

try:
item
print "%s had items" % genOrList
except NameError:
print "%s was empty" % genOrList

checkEmpty(gen( 0))
checkEmpty(gen( 1))
checkEmpty([])
checkEmpty([1])

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

Roy-Smiths-Computer:play$ ./gen.py
<__main__.gen instance at 0x36c620> was empty
<__main__.gen instance at 0x36c620> had items
[] was empty
[1] had items
Jul 19 '05 #3
On Mon, 02 May 2005 16:14:57 -0700, Brian Roberts wrote:
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?


Are you in control of your generators? You could put a method on them that
tells if there is anything in them by manually implementing the .next()
call.

The other thing you could do is a generator wrapper that can tell for you,
but you'll lose some performance:

class EmptyGeneratorD etector(object) :
"""Provides a method you can call to detect an empty
generator. You should probably name this class something
shorter.

Check if the generator is empty after construction by looking at
the isEmpty property."""

def __init__(self, generator):
self.generator = generator

self.isEmpty = False
self.givenFirst = False
try:
self.firstItem = generator.next( )
except StopIteration:
self.isEmpty = True

def next(self):
if self.isEmpty:
raise StopIteration

if not self.givenFirst :
self.givenFirst = True
return self.firstItem
else:
return self.generator. next()

def __iter__(self):
return self

In action:

Python 2.3.5 (#1, Mar 3 2005, 17:32:12)
[GCC 3.4.3 (Gentoo Linux 3.4.3, ssp-3.4.3-0, pie-8.7.6.6)] on linux2
Type "help", "copyright" , "credits" or "license" for more information.
from genwrap import *
def emptyGenerator( ): .... raise StopIteration
.... yield None
.... def nonEmptyGenerat or(): .... yield 1
.... yield 2
.... yield 3
.... e = emptyGenerator( )
n = nonEmptyGenerat or()
E = EmptyGeneratorD etector(e)
N = EmptyGeneratorD etector(n)
E.isEmpty True N.isEmpty False for i in E: .... print i
.... for i in N: .... print i
....
1
2
3


It is tested as much as you see it above :-)

(I recall a lengthy discussion of the best way to create an empty iterator
a while back, and that was not the winner. But it will do for now.)
Jul 19 '05 #4
On 2 May 2005 16:14:57 -0700, br***@mirror.or g (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_spec ial_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(someg enerator()):
something(x)
if n == 0:
empty_list_spec ial_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
Jul 19 '05 #5
Starting from Python 2.4 we have tee in the itertools
module, so you can define the following:

from itertools import tee

def is_empty(it):
it_copy = tee(it)[1]
try:
it_copy.next()
except StopIteration:
return True
else:
return False

It works with generic iterables too.

Michele Simionato

Jul 19 '05 #6

"Brian Roberts" <br***@mirror.o rg> wrote in message
news:50******** *************** **@posting.goog le.com...
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.


If you write an iterator class instead of the abbreviated generator form,
and you can tell from the initialization parameters whether there will be
any data, then you can give the class a __nonzero__ method. You can also
have an initially nonempty iterator flag when it becomes empty.

My point is that writing an iterator as a generator is a convenience, not a
necessity, and that one gives up the full flexibility of an iterator class
when one does so, but that one is not required to do so.

I quite understanding wanting to have your cake and eat it too. The
convenience is sometimes major.

Terry J. Reedy

Jul 19 '05 #7
Jeremy Bowers wrote:
def __init__(self, generator):
self.generator = generator


You'll want to use iter(generator) there in order to handle reiterables.
Jul 19 '05 #8
On Wed, 04 May 2005 13:45:00 +0000, Leif K-Brooks wrote:
Jeremy Bowers wrote:
def __init__(self, generator):
self.generator = generator


You'll want to use iter(generator) there in order to handle reiterables.


Can you expand that explanation a bit? I'm not certain what you mean. I'm
just trusting what the user passes in; maybe the user should pass it
iter(generator) when it's a "reiterable "? (Honest question.)

What definition of "re-iterable" are you using? (A quick google for
"Python reiterabile" just turns up some Python dev list entries from 2003.)

Jul 19 '05 #9
Jeremy Bowers wrote:
On Wed, 04 May 2005 13:45:00 +0000, Leif K-Brooks wrote:

Jeremy Bowers wrote:
def __init__(self, generator):
self.generator = generator


You'll want to use iter(generator) there in order to handle reiterables.

Can you expand that explanation a bit? I'm not certain what you mean. I'm
just trusting what the user passes in; maybe the user should pass it
iter(generator) when it's a "reiterable "? (Honest question.)

What definition of "re-iterable" are you using? (A quick google for
"Python reiterabile" just turns up some Python dev list entries from 2003.)


Reiterable is generally defined as an object which can be iterated over
multiple times (i.e. is iterable but isn't an iterator). The simplest
example is a list, but a few other built-in types (set and dict, for
instance) also qualify.

With the EmptyGeneratorD etector class as you defined it, lists will fail:
EmptyGeneratorD etector([])

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 15, in __init__
AttributeError: 'list' object has no attribute 'next'

Of course, the class is labeled as an empty generator detector, not an
empty iterable detector, so it's doing what it says it will, but a
little bit of extra generalism can't hurt.
Jul 19 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

23
3774
by: Francis Avila | last post by:
Below is an implementation a 'flattening' recursive generator (take a nested iterator and remove all its nesting). Is this possibly general and useful enough to be included in itertools? (I know *I* wanted something like it...) Very basic examples: >>> rl = , '678', 9]] >>> list(flatten(rl)) >>> notstring = lambda obj: not isinstance(obj, type(''))
9
2700
by: Francis Avila | last post by:
A little annoyed one day that I couldn't use the statefulness of generators as "resumable functions", I came across Hettinger's PEP 288 (http://www.python.org/peps/pep-0288.html, still listed as open, even though it's at least a year old and Guido doesn't seem very hot on the idea). I'm not too sure of its ideas on raising exceptions in generators from outside (although it looks like it might be convenient in some cases), but being able...
3
2297
by: Michael Sparks | last post by:
Hi, I'm posting a link to this since I hope it's of interest to people here :) I've written up the talk I gave at ACCU Python UK on the Kamaelia Framework, and it's been published as a BBC R&D White Paper and is available here: * http://www.bbc.co.uk/rd/pubs/whp/whp113.shtml
24
4021
by: Lasse Vågsæther Karlsen | last post by:
I need to merge several sources of values into one stream of values. All of the sources are sorted already and I need to retrieve the values from them all in sorted order. In other words: s1 = s2 = s3 = for value in ???(s1, s2, s3):
6
1498
by: Joachim Worringen | last post by:
I need to process large lists (in my real application, this is to parse the content of a file). I noticed that the performance to access the individual list elements degrades over runtime. This can be reproduced easily using this code: import time N=100000 p=10000
33
56553
by: christophertidy | last post by:
Hi I am new to Python and have recieved this error message when trying to instantiate an object from a class from another file within the same directory and wondered what I have done wrong. I have a Step.py class: class Step(object) def __init__(self, sName): "Initialise a new Step instance"
20
24750
by: Sun | last post by:
Maybe this is a very primative question, but I just get a bit confused about 'set' and 'Set' module in python. I understand 'set' is a build in type in python after 2.4(or 2.3) and Set a seperate module, anyhow, I gonna use build in 'set'. then the question is how can I declare a empty set variable as a 'var= ' do to a list variable?
13
1845
by: Martin Sand Christensen | last post by:
Hi! First a bit of context. Yesterday I spent a lot of time debugging the following method in a rather slim database abstraction layer we've developed: ,---- | def selectColumn(self, table, column, where={}, order_by=, group_by=): | """Performs a SQL select query returning a single column
16
1233
by: Yves Dorfsman | last post by:
Is there a way to do: x = x That would return: I am surprised this notation is not supported, it seems intuitive. A concrete example of the sort of thing I want to do:
0
10171
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9991
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
11191
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
10703
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
8268
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
7443
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
6233
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4967
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
4551
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.