带有块的内部产量保持开放的postgres连接

时间:2019-01-10 15:04:59

标签: python generator psycopg2

从下面的生成器进行yield的连接时,postgres连接是否保持活动状态?还是需要减少yield的缩进量,以便在每个next()上都建立一个新的连接? / p>

def getData(start, end):
    with psycopg2.connect("dbname='test' user='user' host='localhost' password='password'") as conn:
        time = start
        while time<end:
            with conn.cursor() as cur:
                cur.execute(query.format(start, time))
                data = cur.fetchall()
            time += one_week
            yield data

1 个答案:

答案 0 :(得分:5)

是的,上下文管理器保持活动状态。 yield 暂停该功能,没有任何退出。

yield不会改变函数内部的执行顺序。该函数只是“暂停”,冻结在yield表达式已执行并产生值的位置。当稍后恢复生成器时(通过在迭代器上调用__next__),该函数将再次在该点继续。生成器暂停时,无法调用with语句__exit__方法,因此无论如何恢复生成器,都不能退出上下文管理器

如果使用@contextmanager decorator创建一个简单的上下文管理器(它本身依赖于生成器来实现!),您会看到这种情况:

import sys
from contextlib import contextmanager

@contextmanager
def loud_contextmanager():
    print("Context entered!")
    try:
        yield "value to bind the 'as' target to"
    finally:
        exc_info = sys.exc_info()
        if exc_info:
            print("Context exited with an exception!", exc_info)
        else:
            print("Context exited!")

def generator_stages():
    yield "First yield, outside of a context manage"
    with loud_contextmanager() as cm_as_value:
        yield f"Inside of the with block, received {cm_as_value}"
    yield "Outside of with block, last yield"

当您从生成器中提取值进行打印时,您将看到:

>>> gen = generator_stages()
>>> print(next(gen))
First yield, outside of a context manage
>>> print(next(gen))
Context entered!
Inside of the with block, received value to bind the 'as' target to
>>> print(next(gen))
Context exited with an exception! (None, None, None)
Outside of with block, last yield
>>> next(gen, "generator was done")
'generator was done'

请注意,只有在我们检索到第三个值后,上下文才会退出!在第二次next()调用之后,代码在with块内的某个点暂停,只有在未暂停时才能退出上下文,并退出{{1}的finally套件}功能可以运行。