全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 python论坛
1357 4
2015-05-08
Generator functions are coded as normal def statements, but use yield statements to return results one at a time,
suspending and resuming their state between each.

Generator expressions are similar to list comprehensions, but they return an object that produces results on demand instead of
building a result list.

The state that generator functions retain when they are suspended includes both their code location, and their entire local scope.
Hence, their local variables retain information between results, and make it available when the functions are resumed.

>>> def gensquares(N):
              for i in range(N):
                   yield i ** 2 # Resume here later

>>> x = gensquares(4)

You get a generator object that supports the iteration protocol. The returned object has a __next__ method
that states the function and resumes it from where it last yielded a value, and raise a StopIteration exception when
the end of the series of values is reached and the function returns. next(X) built-in calls an objects X.__next__()
method for us.


>>> next(x)




二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

全部回复
2015-5-8 23:26:18
Given the simple examples we’re using to illustrate fundamentals, you might be wondering
just why you’d ever care to code a generator at all. In this section’s example, for
instance, we could also simply build the list of yielded values all at once:

>>>
def buildsquares(n):
    res = []
    for i in range(n): res.append(i ** 2)
    return res
>>> for x in buildsquares(5): print(x, end=' : ')
0 : 1 : 4 : 9 : 16 :

For that matter, we could use any of the for loop, map, or list comprehension techniques:
>>>
for x in [n ** 2 for n in range(5)]:
    print(x, end=' : ')
0 : 1 : 4 : 9 : 16 :
>>>
for x in map((lambda n: n ** 2), range(5)):
    print(x, end=' : ')

0 : 1 : 4 : 9 : 16 :

However, generators can be better in terms of both memory use and performance in
larger programs. They allow functions to avoid doing all the work up front, which is
especially useful when the result lists are large or when it takes a lot of computation to
produce each value. Generators distribute the time required to produce the series of
values among loop iterations.

Moreover, for more advanced uses, generators can provide a simpler alternative to
manually saving the state between iterations in class objects—with generators, variables
accessible in the function’s scopes are saved and restored automatically
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2015-5-8 23:28:56
提示: 作者被禁止或删除 内容自动屏蔽
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2015-5-9 01:51:45
In Python 2.5, a send method was added to the generator function protocol. The send
method advances to the next item in the series of results, just like __next__, but also
provides a way for the caller to communicate with the generator, to affect its operation.

Technically, yield is now an expression form that returns the item passed to send, not
a statement (though it can be called either way—as yield X, or A = (yield X)). The
expression must be enclosed in parentheses unless it’s the only item on the right side
of the assignment statement. For example, X = yield Y is OK, as is X = (yield Y) + 42.

When this extra protocol is used, values are sent into a generator G by calling
G.send(value). The generator’s code is then resumed, and the yield expression in the
generator returns the value passed to send. If the regular G.__next__() method (or its
next(G) equivalent) is called to advance, the yield simply returns None.

>>>
def gen():
    for i in range(10):
        X = yield i
        print(X)
>>> G = gen()
>>> next(G) # Must call next() first, to start generator
0
>>> G.send(77) # Advance, and send value to yield expression
77
1
>>> G.send(88)
88
2
>>> next(G) # next() and X.__next__() send None
None
3
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

2015-5-9 02:02:26
generator expressions are just like normal list comprehensions, and support all their syntax --
including if filters and loop nesting -- but they are enclosed in parentheses instead of square
brackets.

>>> [x ** 2 for x in range(4)] # List comprehension: build a list
[0, 1, 4, 9]
>>> (x ** 2 for x in range(4)) # Generator expression: make an iterable
<generator object <genexpr> at 0x00000000029A8288>

and

>>> G = (x ** 2 for x in range(4))
>>> iter(G) is G # iter(G) optional: __iter__ returns self
True
>>> next(G) # Generator objects: automatic methods
0
>>> next(G)
1
>>> next(G)
4
>>> next(G)
9
>>> next(G)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

Generator expressions vs map

>>> list(map(abs, (−1, −2, 3, 4))) # Map function on tuple
[1, 2, 3, 4]
>>> list(abs(x) for x in (−1, −2, 3, 4)) # Generator expression
[1, 2, 3, 4]
>>> list(map(lambda x: x * 2, (1, 2, 3, 4))) # Nonfunction case
[2, 4, 6, 8]
>>> list(x * 2 for x in (1, 2, 3, 4)) # Simpler as generator?
[2, 4, 6, 8]

and

>>> line = 'aaa,bbb,ccc'
>>> ''.join([x.upper() for x in line.split(',')]) # Makes a pointless list
'AAABBBCCC'
>>> ''.join(x.upper() for x in line.split(',')) # Generates results
'AAABBBCCC'
>>> ''.join(map(str.upper, line.split(','))) # Generates results
'AAABBBCCC'
>>> ''.join(x * 2 for x in line.split(',')) # Simpler as generator?
'aaaaaabbbbbbcccccc'
>>> ''.join(map(lambda x: x * 2, line.split(',')))
'aaaaaabbbbbbcccccc'

Both map and generator expressions can also be arbitrarily nested, which supports general
use in programs, and requires a list call or other iteration context to start the
process of producing results.

>>> [x * 2 for x in [abs(x) for x in (−1, −2, 3, 4)]] # Nested comprehensions
[2, 4, 6, 8]
>>> list(map(lambda x: x * 2, map(abs, (−1, −2, 3, 4)))) # Nested maps
[2, 4, 6, 8]
>>> list(x * 2 for x in (abs(x) for x in (−1, −2, 3, 4))) # Nested generators
[2, 4, 6, 8]


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群