1

我正在考虑设计我的函数以结合数据库查询返回生成器。但对迭代器的概念有一些疑问

def func():
    sql =" select some rows "
    dbconn = "connect and open to dtabase code"
    ret = ( execute(sql)  ) <----- returning a generator?
    dbclose <----  I close the db connection here, but it gives me error
    return ret

问题是,当我在主函数中迭代生成器时,我点击“关闭光标时出错”。我应该在 func() 中关闭还是不关闭它?我想当对 func() 的调用结束时,dbconn 变量将超出范围,我不必担心关闭?

 # main function
 for it in func():
     do something with it
 close dbconn here?

我应该如何设计这个?像列表这样的数据结构会更好吗?谢谢

4

3 回答 3

2

您可以使用Context Manager,例如(包含一些伪代码):

from contextlib import contextmanager

@contextmanager
def func():
    sql =" select some rows "
    dbconn = "connect and open to dtabase code"
    yield execute(sql)  # returns this really a generator?
    dbclose #pseudocode, you probably want to put this in a try/finally block

with func() as result:
    for it in result:
         do something with it

当然,这仅在execute(sql)真正返回生成器时才有用。如果在关闭连接之前将所有数据放入列表(因此放入内存),您的问题将过时。

def func():
    sql =" select some rows "
    dbconn = "connect and open to dtabase code"
    ret = list( execute(sql)  ) 
    dbclose # no problem here, since all data is already fetched
    return ret

回应您的评论:

fetchmany如果您的数据库适配器遵循 python DB API 规范,一种有效的方法是多次获取一堆行。

以下代码以 100 个块为单位获取行,并dbclose在执行离开with块时显式调用:

def cursor_iter(cursor, num_of_rows=100):
    while True:
        rows = cursor.fetchmany(num_of_rows)
        if not rows: break
        for row in rows:
            yield row

@contextmanager
def func():
    sql = "select some rows"
    dbconn = connect_and_open_database()
    cursor = dbconn.cursor()
    cursor.execute(sql)
    yield cursor_iter(cursor)
    dbclose()

with func() as result:
    for row in result: 
        do_something(row)
于 2013-09-10T07:31:06.120 回答
1

我没有太多使用数据库的经验,但我认为您应该检索查询结果并将其作为列表返回。如果你真的需要一个迭代器(但我不明白为什么),那么在列表上返回一个迭代器ret

def func():
    sql =" select some rows "
    dbconn = "connect and open to dtabase code"
    ret = execute(sql)              # a list
    dbclose()
    return (elmt for elmt in ret)   # return an iterator over ret 

现在,如果它们存在检索查询的第 n 个元素的方法,例如execute(sql, n)which return Noneifn太大,那么您可以使用 yield:

 def func():
    sql =" select some rows "
    dbconn = "connect and open to dtabase code"

    n = 0
    ret = execute(sql,n)    # return the n-th element
    while ret is not None:
        yield ret
        n += 1
        ret = execute(sql,n)

    dbclose()

现在,这不是我推荐的,主要是因为与数据库的连接在迭代器未完成时保持打开状态。如果某事失败或设计不当,它可能永远不会发生。

于 2013-09-10T09:16:52.033 回答
0

关闭数据库连接后,您无法尝试操作游标我将尝试使用这种方法:

def func(params):
    sql = "query to execute"
    cursor = execute(sql, params)
    return cursor.fetchall() # retrieves all posible results as a sequence of sequences,
                             # i.g. list of tuples(*)

### Main ###
# Open database connection
# Create cursor
for elem in func(): # Call to retrieve desired element's method and do something with that
    # Do something
# Close cursor
# Close database connection

(*) http://www.python.org/dev/peps/pep-0249/

我希望它有帮助

于 2013-09-10T07:53:22.893 回答