473,386 Members | 1,883 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

frange() question

A while ago I found somewhere the following implementation of frange():

def frange(limit1, limit2 = None, increment = 1.):
"""
Range function that accepts floats (and integers).
Usage:
frange(-2, 2, 0.1)
frange(10)
frange(10, increment = 0.5)
The returned value is an iterator. Use list(frange) for a list.
"""
if limit2 is None:
limit2, limit1 = limit1, 0.
else:
limit1 = float(limit1)
count = int(math.ceil(limit2 - limit1)/increment)
return (limit1 + n*increment for n in range(count))

I am puzzled by the parentheses in the last line. Somehow they make
frange to be a generator:
>print type(frange(1.0, increment=0.5))
<type 'generator'>
But I always thought that generators need a keyword "yield". What is
going on here?

George
Sep 20 '07 #1
6 2298
George Trojan wrote:
A while ago I found somewhere the following implementation of frange():
..
..
..
return (limit1 + n*increment for n in range(count))

I am puzzled by the parentheses in the last line. Somehow they make
frange to be a generator:
But I always thought that generators need a keyword "yield". What is
going on here?
That's what's known as a generator expression:

http://docs.python.org/ref/genexpr.html
http://www.python.org/dev/peps/pep-0289/

TJG
Sep 20 '07 #2
On Thu, 20 Sep 2007 09:08:17 -0400, George Trojan wrote:
A while ago I found somewhere the following implementation of frange():

def frange(limit1, limit2 = None, increment = 1.):
"""
Range function that accepts floats (and integers). Usage:
frange(-2, 2, 0.1)
frange(10)
frange(10, increment = 0.5)
The returned value is an iterator. Use list(frange) for a list.
"""
if limit2 is None:
limit2, limit1 = limit1, 0.
else:
limit1 = float(limit1)
count = int(math.ceil(limit2 - limit1)/increment) return (limit1 +
n*increment for n in range(count))

I am puzzled by the parentheses in the last line. Somehow they make
frange to be a generator:
>print type(frange(1.0, increment=0.5))
<type 'generator'>
But I always thought that generators need a keyword "yield". What is
going on here?

George
Consider the following:

def foo():
yield 1
def bar():
return foo()

Still, ``type(bar())`` would be a generator.

I don't want to tell you anything wrong because I don't know how
generators are implemented on the C level but it's more like changing
foo's (or frange's, in your example) return value.

HTH,
Stargaming
Sep 20 '07 #3
George Trojan <ge***********@noaa.govwrites:
A while ago I found somewhere the following implementation of frange():

def frange(limit1, limit2 = None, increment = 1.):
"""
Range function that accepts floats (and integers).
Usage:
frange(-2, 2, 0.1)
frange(10)
frange(10, increment = 0.5)
The returned value is an iterator. Use list(frange) for a list.
"""
if limit2 is None:
limit2, limit1 = limit1, 0.
else:
limit1 = float(limit1)
count = int(math.ceil(limit2 - limit1)/increment)
return (limit1 + n*increment for n in range(count))

I am puzzled by the parentheses in the last line. Somehow they make
frange to be a generator:
>>print type(frange(1.0, increment=0.5))
<type 'generator'>
Functions are never generators, senso stricto. There are "generator
functions", which *return* (or yield) generators when you call them.
It's true sometimes people refer to generator functions as simply
"generators", but in examples like the above, it's useful to remember
that they are two different things.

In this case, frange isn't a generator function, because it doesn't
yield. Instead, it returns the result of evaluating a generator
expression (a generator). The generatator expression plays the same
role as a generator function -- calling a generator function gives you
a generator object; evaluating a generator expression gives you a
generator object. There's nothing to stop you returning that
generator object, which makes this function behave just like a regular
generator function.
John
Sep 20 '07 #4
On Thu, 2007-09-20 at 18:55 +0000, John J. Lee wrote:
Functions are never generators, senso stricto. There are "generator
functions", which *return* (or yield) generators when you call them.
Actually, a generator function is a function that returns a generator.
The generator, in turn, is an object that wraps the iterator protocol
around a resumable function. When the generator's next() method is
called, it resumes its wrapped function that runs until it yields or
finishes. When the wrapped function yields a value, it is suspended, and
the yielded value is returned as the result of next(). If the wrapped
function finished, next() raises StopIteration.

Generators are a special case of iterators. Any object that implements
the iterator protocol (which among other less important things mandates
a next() method that returns the next value or raises StopIteration) is
an iterator. Generators simply have their special way (by calling into a
resumable function) of implementing the iterator protocol, but any
stateful object that returns a value or raises StopIteration in next()
is an iterator.
It's true sometimes people refer to generator functions as simply
"generators", but in examples like the above, it's useful to remember
that they are two different things.

In this case, frange isn't a generator function, because it doesn't
yield. Instead, it returns the result of evaluating a generator
expression (a generator). The generatator expression plays the same
role as a generator function -- calling a generator function gives you
a generator object; evaluating a generator expression gives you a
generator object. There's nothing to stop you returning that
generator object, which makes this function behave just like a regular
generator function.
Generator expressions still "yield", but you don't see the yield in the
Python source code. Observe:
>>def gf1():
.... for i in (1,2,3):
.... yield i
....
>>def gf2():
.... return (i for i in (1,2,3))
....
>>g1 = gf1()
g2 = gf2()
g1
<generator object at 0xb7f66d8c>
>>g2
<generator object at 0xb7f66f4c>
>>dir(g1)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__',
'__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__', 'close', 'gi_frame', 'gi_running',
'next', 'send', 'throw']
>>dir(g2)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__',
'__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__', 'close', 'gi_frame', 'gi_running',
'next', 'send', 'throw']
>>import dis
dis.dis(g1.gi_frame.f_code.co_code)
0 SETUP_LOOP 19 (to 22)
3 LOAD_CONST 4 (4)
6 GET_ITER
> 7 FOR_ITER 11 (to 21)
10 STORE_FAST 0 (0)
13 LOAD_FAST 0 (0)
16 YIELD_VALUE
17 POP_TOP
18 JUMP_ABSOLUTE 7
> 21 POP_BLOCK
22 LOAD_CONST 0 (0)
25 RETURN_VALUE
>>dis.dis(g2.gi_frame.f_code.co_code)
0 SETUP_LOOP 18 (to 21)
3 LOAD_FAST 0 (0)
> 6 FOR_ITER 11 (to 20)
9 STORE_FAST 1 (1)
12 LOAD_FAST 1 (1)
15 YIELD_VALUE
16 POP_TOP
17 JUMP_ABSOLUTE 6
> 20 POP_BLOCK
21 LOAD_CONST 0 (0)
24 RETURN_VALUE

As you can see, except for a minor optimization in the byte code, there
is no discernible difference between the generator that's returned from
a generator expression and the generator that's returned from the
generator function. Note in particular that the byte code for g2
contains a YIELD_VALUE operation just like g1 does.

In fact, generator expressions are merely a short-hand notation for
simple generator functions of a particular form. The generator
expression

g = (expr(x) for x in some_iterable)

produces a generator that is almost indistinguishable from, and
operationally identical to, the generator produced by the following
code:

def __anonymous():
for x in some_iterable:
yield expr(x)
g = __anonymous()
del __anonymous

Hope this helps,

--
Carsten Haese
http://informixdb.sourceforge.net
Sep 20 '07 #5
In article <fc**********@news.nems.noaa.gov>,
George Trojan <ge***********@noaa.govwrote:
A while ago I found somewhere the following implementation of frange():

def frange(limit1, limit2 = None, increment = 1.):
"""
Range function that accepts floats (and integers).
Usage:
frange(-2, 2, 0.1)
frange(10)
frange(10, increment = 0.5)
The returned value is an iterator. Use list(frange) for a list.
"""
if limit2 is None:
limit2, limit1 = limit1, 0.
else:
limit1 = float(limit1)
count = int(math.ceil(limit2 - limit1)/increment)
return (limit1 + n*increment for n in range(count))

I am puzzled by the parentheses in the last line. Somehow they make
frange to be a generator:
>print type(frange(1.0, increment=0.5))
<type 'generator'>
But I always thought that generators need a keyword "yield". What is
going on here?
Hi, George,

The expression returned is a "generator expression",

return (limit1 + n*increment for n in range(count))

Thus, although frange itself is not written as a generator, it does
return a generator as its result. The syntax is like that of list
comprehensions; see:

<http://docs.python.org/ref/genexpr.html>

Cheers,
-M

--
Michael J. Fromberger | Lecturer, Dept. of Computer Science
http://www.dartmouth.edu/~sting/ | Dartmouth College, Hanover, NH, USA
Sep 21 '07 #6
Carsten Haese <ca*****@uniqsys.comwrites:
On Thu, 2007-09-20 at 18:55 +0000, John J. Lee wrote:
>Functions are never generators, senso stricto. There are "generator
functions", which *return* (or yield) generators when you call them.

Actually, a generator function is a function that returns a generator.
Read what I wrote again. What makes you begin your sentence with
"Actually", rather than "Putting it another way"?
[...snip more sensible stuff I must assume was directed at the OP...]
John
Sep 22 '07 #7

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

Similar topics

3
by: Stevey | last post by:
I have the following XML file... <?xml version="1.0"?> <animals> <animal> <name>Tiger</name> <questions> <question index="0">true</question> <question index="1">true</question> </questions>
7
by: nospam | last post by:
Ok, 3rd or is it the 4th time I have asked this question on Partial Types, so, since it seems to me that Partial Types is still in the design or development stages at Microsoft, I am going to ask...
3
by: Ekqvist Marko | last post by:
Hi, I have one Access database table including questions and answers. Now I need to give answer id automatically to questionID column. But I don't know how it is best (fastest) to do? table...
10
by: glenn | last post by:
I am use to programming in php and the way session and post vars are past from fields on one page through to the post page automatically where I can get to their values easily to write to a...
10
by: Rider | last post by:
Hi, simple(?) question about asp.net configuration.. I've installed ASP.NET 2.0 QuickStart Sample successfully. But, When I'm first start application the follow message shown. ========= Server...
53
by: Jeff | last post by:
In the function below, can size ever be 0 (zero)? char *clc_strdup(const char * CLC_RESTRICT s) { size_t size; char *p; clc_assert_not_null(clc_strdup, s); size = strlen(s) + 1;
3
by: forum | last post by:
Hi! what's the standard way for a "for" loop with float increments? Anton
56
by: spibou | last post by:
In the statement "a *= expression" is expression assumed to be parenthesized ? For example if I write "a *= b+c" is this the same as "a = a * (b+c)" or "a = a * b+c" ?
2
by: Allan Ebdrup | last post by:
Hi, I'm trying to render a Matrix question in my ASP.Net 2.0 page, A matrix question is a question where you have several options that can all be rated according to several possible ratings (from...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
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,...
0
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...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

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.