-1

我在python中练习使用生成器函数,所以我定义了一个函数如下:

def MySQL_product():
   #Establish connection to database
   try:
       connection = msql.connect(host = 'localhost', user = 'max', passwd = 'password', db = 'schools')
   except:
       pass

   #Iterate through each product and insert them in database
   with connection:
       cursor = connection.cursor()
       cursor.execute("SELECT name, age, gender, school
                    WHERE GroupId = 'student' AND Exchange = 'foreign'")
       for product in cursor.fetchall():
           yield product

def main():
    for column in range (0, number_of_schools):
        for product in MySQL_product():
            print product

但是,当我运行此代码时,我看到的所有输出都是generator object at ...我正在尝试打印在数据库中找到的内容。此外,没有执行任何print语句MySQL_product()。生成器的要点是,它应该一一返回,而不是返回数据库中所有行的列表。然后我想访问/打印这些项目。我该怎么做才能修复此代码?

4

3 回答 3

5

如果您正在执行 cursor.fetchall(),这意味着您正在将 SQL 服务器中可用的每个结果复制到 python 的内存中。因此,在这种情况下 - 生成器不会为您提供任何东西。

如果您改为使用 cursor.fetchmany() 或 cursor.fetchone(),您会看到的唯一好处是 Python 方面的内存消耗,因为您一次只能处理“一些”或“一个”结果。在 SQL 端,服务器仍会缓存该结果集(消耗 SQL 服务器上的宝贵资源)

但是,最终 - 如果您确实处理了大块的结果 - 因为您将处于以下循环中:

while there_are_more_results:
    results = cursor.fetchmany(10)
    for result in results:
        do_something(result)

拥有生成器不会为您提供任何真正的优势,因为当您从 mysql 获得更多结果时,您将不得不阻塞。

但是,要回答您的问题

您想要使您拥有的代码工作的是:

def main():
    for column in range (0, number_of_schools):
        for student in MySQL_product():
            print student

当您以异步方式执行操作时,生成器非常有用 - 基本上如果生成器还没有准备好 - 您只需跳过它并让其他事情工作。

于 2013-08-06T01:57:00.660 回答
2

是的,这就是生成器的行为方式——它总是返回一个迭代器,然后您可以将其与例如for语句一起使用。您可能希望将main()功能更改为如下所示:

def main():
    for column in range (0, number_of_schools):
        for student in MySQL_product():
            print student

也可以使用该函数获得由迭代器产生的下一个结果next(),但通常您应该更喜欢直接迭代for item in iterator: # ...(因为您的代码将更易于阅读,并且在您执行类似 switch back from生成器函数到返回列表的常规函数​​)。

于 2013-08-06T01:59:57.163 回答
0

我的第一个答案是不正确的,其他人已经给出了最好的解决方案,所以我将说明替代方案和潜在的用例。如果您需要一次迭代生成器两个项目,或者以任何其他自定义方式,该next方法可能很有用。

def gen():
    for i in range(20):
        yield i

for i in gen():
    print "Center", str(i).center(10)

a = gen()    
for i in range(10):
    left = str(a.next()).ljust(10)
    right = str(a.next()).rjust(10)
于 2013-08-06T01:53:40.963 回答