2013-10-16 5 views
4

Я пытаюсь написать генераторную функцию, которая получает строки из базы данных и возвращает их по одному. Тем не менее, я не уверен, что код очистки, помеченный ** ниже, выполняется, как я думаю. Если это не так, как лучше всего поместить код очистки внутри самого генератора, который выполняется после последней инструкции yield? Я посмотрел на ловушку StopIteration, но это, похоже, сделано от вызывающего, а не внутри генератора.лучший способ запустить код очистки генератора python

def MYSQLSelectGenerator(stmt): 
... 
try: 
    myDB = MySQLdb.connect(host=..., port=..., user=..., passwd=..., db=...) 
    dbc=myDB.cursor() 
    dbc.execute(stmt) 
    d = "asdf" 
    while d is not None: 
     d = dbc.fetchone() #can also use fetchmany() to be more efficient 
     yield d 
    dbc.close() #** DOES THIS WORK AS I INTEND, MEANING AS SOON AS d = "None" 
except MySQLdb.Error, msg: 
    print("MYSQL ERROR!") 
    print msg 
+0

У вас нет опыта, но вы можете добавить предложение '' 'finally''' и поместить туда чистку - похоже, именно так оно и предназначалось. [** ** ** **) (http://docs.python.org/2.7/reference/compound_stmts.html#the-try-statement) – wwii

ответ

1

Вы можете использовать менеджер контекста и with заявление. contextlib обеспечивает closing:

from contextlib import closing 

myDB = MySQLdb.connect(host=..., port=..., user=..., passwd=..., db=...) 
with closing(myDB.cursor()) as dbc: 
    dbc.execute(stmt) 
    d = "asdf" 
    while d is not None: 
     d = dbc.fetchone() #can also use fetchmany() to be more efficient 
     yield d 

Это автоматически вызовет close() на dbc в конце with блока, даже если исключение было возбуждено.

+0

Я официально принял ответ Бена, но этот ответ более правильный, поскольку менеджеры контекста уже справляются с этой сложностью. – Tommy

3

Ваша версия будет работать dbc.close() как только d is None, но не исключение, если получает поднятый. Вам нужен finally clause. Эта версия гарантированно запустить dbc.close() даже если исключение получает поднятый:

try: 
    myDB = MySQLdb.connect(host=..., port=..., user=..., passwd=..., db=...) 
    dbc = myDB.cursor() 
    dbc.execute(stmt) 
    d = "asdf" 
    while d is not None: 
     d = dbc.fetchone() #can also use fetchmany() to be more efficient 
     yield d 
except MySQLdb.Error, msg: 
    print("MYSQL ERROR!") 
    print msg 
finally: 
    dbc.close() 
+0

Есть ли способ объединить два? Проблема с этим подходом заключается в том, что dbc.close() больше не находится в блоке try, который улавливает ошибки mysql, как это было в моей версии. Является ли ответ поставить другой блок try в предложение finally? thats уродливый, но .. – Tommy

+0

Хороший дизайн API диктует, что такие методы, как 'close', не должны генерировать исключения (кроме случаев, когда соединение уже закрыто), потому что клиенты останутся в состоянии, когда вы не уверены, соединение очищено или нет. Вы должны подтвердить это с авторами соответствующей библиотеки, но я подозреваю, что было бы безопасно предположить, что исключений из этой строки не будет. –

3

Одна вещь, которую вы могли бы сделать, это использовать пункт finally. Другой вариант (который может быть излишним здесь, но это полезная вещь, чтобы знать о), чтобы сделать класс, который работает с with заявлением:

class DatabaseConnection: 
    def __init__(self, statement): 
     self.statemet = statement 
    def __enter__(self): 
     self.myDB = MySQLdb.connect(host=..., port=...,user=...,passwd=...,db=...) 
     self.dbc = myDB.cursor() 
     self.dbc.execute(self.statement) 
     self.d = "asdf" 
    def __exit__(self, exc_type, exc_value, traceback): 
     self.dbc.close() 

    def __iter__(self): 
     while self.d is not None: 
      self.d = self.dbc.fetchone() 
      yield self.d 


with DatabaseConnection(stmnt) as dbconnection: 
    for i in dbconnection: 
     print(i) 
Смежные вопросы