Python yield expression (generator)

  1. When a function has a "yield" expression, it is a generator.
  2. A generator doesn't run until it is called with next(g) or g.next(). 
  3. The first time to call a function which has "yield expression", it is returning a generator object, say gen = echo([11,...]) below,  gen is an generator object.
  4. Every time, gen.next (or next(gen)) is called, 
    • If it is the first time to call "next", the generator executes until it reaches "yield expression". When the generator hits "yield expression", the value just behind the keyword "yield" is returned to caller. For eg, return "val" in the "yield val" expression in the following code. Please notice that the "yield expression" itself doesn't return (UNTIL "next/send" etc is called again against this generator)
    • If it is not the first time to call "next", the generator resumes to execute just at the point where the "yield expression" paused at the very last time. At this very time, the "yield expression" returns (None by default). The generator executes until it reaches the next "yield" expression.
  5. "yield" expression itself usually returns "None", unless we send a explicit value to the "yield" expression by calling "send(val)". For, eg, val = (yield val), val on the left side usually have None value, but if we call this generator with send(20), then val on the left side will have value with 20.
  6. When a generator is closed (call its "close()" method), we can't call next on it anymore, it will throw StopIteration exception. When "close()" is called against a generator, an "GeneratorExit" exception will be thrown inside the generator, which will terminate the iteration. So there is one last chance to do post processing by catching this exception. Take the following code for eg, before the "echo" generator is exhausted, if "close()" is called, "GeneratorExit" exception will be thrown automatically, and "GeneratorExit exception thrown..." will be printed.
  7. When a generator is garbage collected, "close()" is called automatically.
  8. We can explicitly feed an exception to a generator (to terminate the iteration maybe) by calling "throw()" method. The exception is raised by the "yield expression" where the generator’s execution is paused.
  9. Always remember to put parentheses around a "yield expression" when you’re doing something with the returned value. (Can you tell the difference between "val = yield val + 10" and "val = (yield val) + 10" ?)
  10. Generator has great flexibility and memory efficiency if we just loop through some iterable and process one item at a time.
  11. Generator expression has more memory efficiency than list comprehension 
    for x, y in ((x, y) for x in a for y in b): print x, y  # generator expression
    for x, y in [(x, y) for x in a for y in b]: print x, y  # list comprehension

def echo(arr):

    print('Execution start when next() is called for the first time.');
    try:
        siz = len(arr)
        i = 0
        val = None
        while True:
            try:
                if i < siz:
                    print ('before yielding...{0}'.format(val))
                    val = arr[i]
                    # When hitting the following yield expr, "val" is returned to the caller, 
                    # but the expr itself is not returned until "next/again" is called again
                    val = (yield val)
                    print ('after yielding: {0}'.format(val))
                    i += 1
                else:
                    raise StopIteration()
            except Exception as e:
                print('Other exception thrown %s' %str(e))
                raise e
            except GeneratorExit as e:
                # Please rethrow this exception or rethrow StopIteration exception
                # Otherwise "runtime error" will be triggered.
                # Note GeneratorExit is not an error
                print('GeneratorExit exception thrown %s' %str(e))
                raise e
    finally:
        # When "close()" is called or the generator garbage-collected, 
        # this section of code is executed 
        print("Don't forget to clean up when close() is called.")


gen = echo([11, 12, 13, 14])
print type(gen)
print(next(gen))
#print(next(gen))
print(gen.send(20))
#gen.throw(TypeError, 'Spam')
gen.close()
print(next(gen))
#for i in gen:
#    print(i)


def counter(start_at=0):
    count = start_at
    while True:
        val = (yield count)
        if val is not None:
            count = val
        else:
            count += 1


#count = counter(5)
#print count.next()
#print count.send(9)
#print count.next()
#print count.next()

An other example:
---
def paragraphs(lines, is_separator=str.isspace, joiner=''.join):
    paragraph = [ ]
    for line in lines:
        if is_separator(line):
            if paragraph:
                yield joiner(paragraph)
                paragraph = del [:]
        else:
            paragraph.append(line)
    if paragraph:
        yield joiner(paragraph)

if __name__ == '__main__':
    text = 'a first\nparagraph\n\nand a\nsecond one\n\n'
    for p in paragraphs(text.splitlines(True)): 
        print repr(p)

Yet another example:
---
def fetchsome(cursor, arraysize=1000):
    ''' A generator that simplifies the use of fetchmany '''
    while True:
        results = cursor.fetchmany(arraysize)

    if not results: break
        for result in results:
            yield result
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中,`yield`关键字用于定义生成器函数。生成器函数是一种特殊的函数,它可以产生一个迭代器对象,通过迭代器可以逐步产生值而不是一次性返回所有结果。生成器函数使用`yield`语句来指示函数在每次被调用时暂停执行,并返回一个值给调用者。调用者可以通过调用生成器的`next()`方法或使用`for`循环来逐步获取生成器产生的值。 除了在生成器函数中使用`yield`语句来控制生成器的执行流程外,`yield`还可以与其他语句和表达式一起使用,例如`send()`方法可以在生成器中发送一个值,并将其作为`yield`表达式的结果,`throw()`方法用于在生成器中引发一个异常,`close()`方法用于关闭生成器。 PEP342进一步增强了生成器函数的功能,将`yield`从一个关键字(statement)变为表达式(expression),并引入了`send()`,`throw()`,`close()`等方法来操作生成器。这些增强使得生成器函数更加灵活和功能强大。 通过使用生成器函数,我们可以按需生成序列中的值,而不需要一次性生成所有的值,这样可以节省内存并提高效率。此外,生成器函数还可以用于实现协程和异步编程等高级应用。 参考文献: PEP 342 -- Coroutines via Enhanced Generators: https://www.python.org/dev/peps/pep-0342/ Real Python - Introduction to Python Generators: Using Advanced Generator Methods: https://realpython.com/introduction-to-python-generators/#using-advanced-generator-methods Real Python - Generators in Python: Creating and Iterating Simple Generators: https://realpython.com/introduction-to-python-generators/<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python yield关键字全面解析](https://blog.csdn.net/jeffery0207/article/details/124856788)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值