[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Re: How to make an empty generator?

Robert Kern

2/18/2010 11:31:00 PM

On Feb 18, 5:08 pm, Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> wrote:
> On 2010-02-18 16:25 PM, Stephen Hansen wrote:
>
> > This has to be a stupid question, but :)
>
> > I have some generators that do stuff, then start yielding results. On
> > occasion, I don't want them to yield anything ever-- they're only
> > really "generators" because I want to call them /as/ a generator as
> > part of a generalized system.
>
> > The only way I can figure out how to make an empty generator is:
>
> > def gen():
> > # do my one-time processing here
>
> > return
> > yield
>
> If all you want is a generator that doesn't yield anything, then surely
> there isn't any one-time processing and you don't need the comment?

Sure there is. Python doesn't know that nothing gets yielded until it hits the
return statement before the yield. When it calls .next() on the iterator, the
code elided by the comment executes, then the return is hit, a StopIteration
exception is raised, and the iteration is complete.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

12 Answers

Steven D'Aprano

2/19/2010 12:32:00 AM

0

On Thu, 18 Feb 2010 17:30:54 -0600, Robert Kern wrote:

> > If all you want is a generator that doesn't yield anything, then
> > surely there isn't any one-time processing and you don't need the
> > comment?
>
> Sure there is. Python doesn't know that nothing gets yielded until it
> hits the return statement before the yield. When it calls .next() on the
> iterator, the code elided by the comment executes, then the return is
> hit, a StopIteration exception is raised, and the iteration is complete.

I don't understand why you care about having *any* code before the
StopIteration. That's like:

def empty():
for x in range(1000):
pass # Spin wheels uselessly
return
yield


What's the point of the wheel spinning? Did I miss something?



--
Steven

Mel

2/19/2010 1:29:00 AM

0

Steven D'Aprano wrote:

> On Thu, 18 Feb 2010 17:30:54 -0600, Robert Kern wrote:
>
>> > If all you want is a generator that doesn't yield anything, then
>> > surely there isn't any one-time processing and you don't need the
>> > comment?
>>
>> Sure there is. Python doesn't know that nothing gets yielded until it
>> hits the return statement before the yield. When it calls .next() on the
>> iterator, the code elided by the comment executes, then the return is
>> hit, a StopIteration exception is raised, and the iteration is complete.
>
> I don't understand why you care about having *any* code before the
> StopIteration. That's like:
>
> def empty():
> for x in range(1000):
> pass # Spin wheels uselessly
> return
> yield
>
>
> What's the point of the wheel spinning? Did I miss something?

I wonder whether it's for some kind of framework with a main loop like

for it in list_of_iterables:
for x in it:
do_this_or_that (x)

where, every once in a while one wants to throw some arbitrary code into the
process, in the form of an empty iterable with side effects.

Mel.


Robert Kern

2/19/2010 6:15:00 AM

0

On 2010-02-18 19:28 PM, Mel wrote:
> Steven D'Aprano wrote:
>
>> On Thu, 18 Feb 2010 17:30:54 -0600, Robert Kern wrote:
>>
>>> > If all you want is a generator that doesn't yield anything, then
>>> > surely there isn't any one-time processing and you don't need the
>>> > comment?
>>>
>>> Sure there is. Python doesn't know that nothing gets yielded until it
>>> hits the return statement before the yield. When it calls .next() on the
>>> iterator, the code elided by the comment executes, then the return is
>>> hit, a StopIteration exception is raised, and the iteration is complete.
>>
>> I don't understand why you care about having *any* code before the
>> StopIteration. That's like:
>>
>> def empty():
>> for x in range(1000):
>> pass # Spin wheels uselessly
>> return
>> yield
>>
>>
>> What's the point of the wheel spinning? Did I miss something?
>
> I wonder whether it's for some kind of framework with a main loop like
>
> for it in list_of_iterables:
> for x in it:
> do_this_or_that (x)
>
> where, every once in a while one wants to throw some arbitrary code into the
> process, in the form of an empty iterable with side effects.

Yes. That is exactly what the OP said in his original post:

"""
I have some generators that do stuff, then start yielding results. On occasion,
I don't want them to yield anything ever-- they're only really "generators"
because I want to call them /as/ a generator as part of a generalized system.
"""

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Steven D'Aprano

2/19/2010 6:22:00 AM

0

On Fri, 19 Feb 2010 00:15:20 -0600, Robert Kern wrote:

>>> What's the point of the wheel spinning? Did I miss something?
>>
>> I wonder whether it's for some kind of framework with a main loop like
>>
>> for it in list_of_iterables:
>> for x in it:
>> do_this_or_that (x)
>>
>> where, every once in a while one wants to throw some arbitrary code
>> into the process, in the form of an empty iterable with side effects.
>
> Yes. That is exactly what the OP said in his original post:
>
> """
> I have some generators that do stuff, then start yielding results. On
> occasion, I don't want them to yield anything ever-- they're only really
> "generators" because I want to call them /as/ a generator as part of a
> generalized system. """


But he doesn't say anything about side-effects. If you're passing
generators around, sometimes you want an empty generator, just as
sometimes you want an empty string, or list, or whatever.



--
Steven

Robert Kern

2/19/2010 3:52:00 PM

0

On 2010-02-19 00:21 AM, Steven D'Aprano wrote:
> On Fri, 19 Feb 2010 00:15:20 -0600, Robert Kern wrote:
>
>>>> What's the point of the wheel spinning? Did I miss something?
>>>
>>> I wonder whether it's for some kind of framework with a main loop like
>>>
>>> for it in list_of_iterables:
>>> for x in it:
>>> do_this_or_that (x)
>>>
>>> where, every once in a while one wants to throw some arbitrary code
>>> into the process, in the form of an empty iterable with side effects.
>>
>> Yes. That is exactly what the OP said in his original post:
>>
>> """
>> I have some generators that do stuff, then start yielding results. On
>> occasion, I don't want them to yield anything ever-- they're only really
>> "generators" because I want to call them /as/ a generator as part of a
>> generalized system. """
>
> But he doesn't say anything about side-effects.

"I have some generators *that do stuff*, then start yielding results." [emphasis
mine]. Then he gives an example of a generator that does side-effect stuff and
returning before yielding anything.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Steven D'Aprano

2/19/2010 5:21:00 PM

0

On Fri, 19 Feb 2010 09:51:54 -0600, Robert Kern wrote:

> On 2010-02-19 00:21 AM, Steven D'Aprano wrote:
>> On Fri, 19 Feb 2010 00:15:20 -0600, Robert Kern wrote:
>>
>>>>> What's the point of the wheel spinning? Did I miss something?
>>>>
>>>> I wonder whether it's for some kind of framework with a main loop
>>>> like
>>>>
>>>> for it in list_of_iterables:
>>>> for x in it:
>>>> do_this_or_that (x)
>>>>
>>>> where, every once in a while one wants to throw some arbitrary code
>>>> into the process, in the form of an empty iterable with side effects.
>>>
>>> Yes. That is exactly what the OP said in his original post:
>>>
>>> """
>>> I have some generators that do stuff, then start yielding results. On
>>> occasion, I don't want them to yield anything ever-- they're only
>>> really "generators" because I want to call them /as/ a generator as
>>> part of a generalized system. """
>>
>> But he doesn't say anything about side-effects.
>
> "I have some generators *that do stuff*, then start yielding results."
> [emphasis mine].

What does "do stuff" have to do with side-effects? Here's a generator
that does stuff, and it has no side-effects.

def generator_that_does_stuff(x):
y = 3*x**2 - 5*x + 1
yield y

"Do stuff" is ambiguous -- it could mean stuff with side-effects, or
stuff without. The first is potentially harmful, the second is pointless.


> Then he gives an example of a generator that does
> side-effect stuff and returning before yielding anything.

Unfortunately the OP's original post isn't visible to me, so I can only
respond to your post, which may or may not quote the entire original post.

The only example I have seen was an empty generator with a comment saying
"do my one-time processing here", with *no* indication of what that one-
time processing is supposed to be, why it is necessary, and whether it
has side-effects or not.

Since the OP (apparently) hasn't seen fit to comment, we're still all
guessing what he means. It's certainly possible, likely even, that he's
using generators that operate by side-effect: that explanation is
consistent with his request. Personally, I can't imagine that would be
good coding practice, but I could be wrong.


--
Steven

Terry Reedy

2/19/2010 7:25:00 PM

0

On 2/19/2010 12:44 PM, Stephen Hansen wrote:

> Much to my embarrassment, sometime last night I realized I was being a
> complete idiot, and the 'correct' way to handle this in my scenario is
> really just:
>
> def initialize():
> # do one time processing here
>
> return []
>
> A generator is just a callable that returns an iterator, after all.

Confusing generators and generator functions is, well, confusing.
For future reference, and clarity of communication in Pythonland,

generator function: function that produces a generator when called; if
python coded, its body contains 'yield'.

generator: iterator produced by a generator function; has .__next__ and
self-returning .__init__, like all other iterators.

generator expression: an expression that evaluates to a generator; the
expression is used to create a temporary anonymous generator function
that is called to produce the generator and is then discarded.

>>> def gf(): yield 1

>>> gf
<function gf at 0x00F5F4B0>
>>> g=gf()
>>> g
<generator object gf at 0x00F5BE40>
>>> ge = (1 for i in [1])
>>> ge
<generator object <genexpr> at 0x00F5BFD0>
>>> dir(ge)
[..., '__iter__', ..., '__next__', ...]

So, when you said that you send 'generators' to your core system, when
you meant 'generator functions', we were understanably confused. (Your
core system should accept iterator classes also, unless it specifically
checks to avoid duck typing.)

Terry Jan Reedy

John Posner

2/19/2010 8:16:00 PM

0

On 2/19/2010 2:25 PM, Terry Reedy wrote:
> On 2/19/2010 12:44 PM, Stephen Hansen wrote:
>
>> Much to my embarrassment, sometime last night I realized I was being a
>> complete idiot, and the 'correct' way to handle this in my scenario is
>> really just:
>>
>> def initialize():
>> # do one time processing here
>>
>> return []
>>
>> A generator is just a callable that returns an iterator, after all.
>
> Confusing generators and generator functions is, well, confusing.
> For future reference, and clarity of communication in Pythonland,
>
> generator function: function that produces a generator when called; if
> python coded, its body contains 'yield'.
>
> generator: iterator produced by a generator function;

I suggest:

iterator produced by a generator function or a generator expression;

has .__next__ and
> self-returning .__init__, like all other iterators.
>
> generator expression: an expression that evaluates to a generator; the
> expression is used to create a temporary anonymous generator function
> that is called to produce the generator and is then discarded.

Note that the Py2.6.4 documentation is inconsistent. AFAICT, it conforms
to Terry's definitions above in most places. But the Glossary says:

generator
A function which returns an iterator. <... more ...>

generator expression
An expression that returns a generator. <... more ...>

The additional verbiage in these definitions mitigates the damage, but I
think the first entry should be headlined *generator function* instead
of *generator*. And the Glossary should include Terry's additional entry
[ as amended by me :-) ]:

generator
An iterator produced by a generator function or a generator
expression.

-John

Steve Holden

2/24/2010 2:07:00 PM

0

John Posner wrote:
> On 2/19/2010 2:25 PM, Terry Reedy wrote:
>> On 2/19/2010 12:44 PM, Stephen Hansen wrote:
>>
>>> Much to my embarrassment, sometime last night I realized I was being a
>>> complete idiot, and the 'correct' way to handle this in my scenario is
>>> really just:
>>>
>>> def initialize():
>>> # do one time processing here
>>>
>>> return []
>>>
>>> A generator is just a callable that returns an iterator, after all.
>>
>> Confusing generators and generator functions is, well, confusing.
>> For future reference, and clarity of communication in Pythonland,
>>
>> generator function: function that produces a generator when called; if
>> python coded, its body contains 'yield'.
>>
>> generator: iterator produced by a generator function;
>
> I suggest:
>
> iterator produced by a generator function or a generator expression;
>
> has .__next__ and
>> self-returning .__init__, like all other iterators.
>>
>> generator expression: an expression that evaluates to a generator; the
>> expression is used to create a temporary anonymous generator function
>> that is called to produce the generator and is then discarded.
>
> Note that the Py2.6.4 documentation is inconsistent. AFAICT, it conforms
> to Terry's definitions above in most places. But the Glossary says:
>
> generator
> A function which returns an iterator. <... more ...>
>
> generator expression
> An expression that returns a generator. <... more ...>
>
> The additional verbiage in these definitions mitigates the damage, but I
> think the first entry should be headlined *generator function* instead
> of *generator*. And the Glossary should include Terry's additional entry
> [ as amended by me :-) ]:
>
> generator
> An iterator produced by a generator function or a generator
> expression.
>
> -John
>
+1. Can someone submit a documentation patch, please?

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010 http://us....
Holden Web LLC http://www.hold...
UPCOMING EVENTS: http://holdenweb.event...

John Posner

2/24/2010 2:49:00 PM

0

On 2/24/2010 9:07 AM, Steve Holden wrote:
> John Posner wrote:

>> Note that the Py2.6.4 documentation is inconsistent. AFAICT, it conforms
>> to Terry's definitions above in most places. But the Glossary says:
>>
>> generator
>> A function which returns an iterator.<... more ...>
>>
>> generator expression
>> An expression that returns a generator.<... more ...>
>>
>> The additional verbiage in these definitions mitigates the damage, but I
>> think the first entry should be headlined *generator function* instead
>> of *generator*. And the Glossary should include Terry's additional entry
>> [ as amended by me :-) ]:
>>
>> generator
>> An iterator produced by a generator function or a generator
>> expression.
>>
>> -John
>>
> +1. Can someone submit a documentation patch, please?
>

Will do. -John