5

编写以下生成器函数是否比仅.fetchone()在 while 循环中调用有优势?如果是这样,那将是什么优势?

谢谢。

def testf2():
    db = connectToMysqlDB(None)

    sql_statement = " ".join([
        "select d.* ",
        "from dr_snapshot d ",
        "order by d.PremiseID asc, d.last_read asc; "])

    sel_cur = db.cursor()
    rc = sel_cur.execute(sql_statement)

    loop_ok = True
    while loop_ok:
        meter_row = sel_cur.fetchone()
        if meter_row:
            yield meter_row
        else:
            loop_ok = False

    yield None

for read_val in testf2():
   print(read_val)
   #Perform something useful other than print.

('610159000', 6, datetime.datetime(2012, 7, 25, 23, 0), 431900L, 80598726L)
('610160000', 6, datetime.datetime(2012, 7, 25, 23, 0), 101200L, 80581200L)
None
4

3 回答 3

5

没有。从功能上讲,它们是相同的,但是如果您想重用代码,将其包装在生成器中会有好处。例如,您可以添加代码以在完成生成器块中的读取后关闭连接/光标。我建议您将其添加到上面的代码中,以便关闭游标。

def testf2():
    try:
        db = connectToMysqlDB(None)

        sql_statement = " ".join([
            "select d.* ",
            "from dr_snapshot d ",
            "order by d.PremiseID asc, d.last_read asc; "])

        sel_cur = db.cursor()
        rc = sel_cur.execute(sql_statement)

        loop_ok = True
        while loop_ok:
            meter_row = sel_cur.fetchone()
            if meter_row:
                yield meter_row
            else:
                loop_ok = False
    except ProgrammingError:
        print "Tried to read a cursor after it was already closed"
    finally:
        sel_cur.close()

这将使重用变得更容易,因为您只需在一个地方进行连接管理。

于 2012-07-27T17:18:05.323 回答
4

看起来我是对的,mySQL 游标可迭代的(https://stackoverflow.com/a/1808414/138772)。所以你可以这样做而不是你的while循环(但我喜欢将数据库访问代码放在生成器函数中的想法,所以保留它):

for meter_row in sel_cur:
    yield meter_row

另请注意,您可能不想要那个 final yield NoneStopIteration异常用于指示迭代器输出的耗尽,并且是循环for用作其标志来停止循环的,因此通过在输出末尾包含yield None你最终None没有真正的增益。

于 2012-07-27T17:22:18.177 回答
0

使用生成器为您在现有代码中使用结果提供了额外的灵活性。例如,您可以将其直接传递给csv.writer writerows函数。

于 2012-07-27T17:35:51.520 回答