2013-10-16 89 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'''子句並將清理放在那裏 - 看起來就是它的目的。 [The ** try ** statement](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 

這會自動調用上dbcclose()with塊的末尾,即使一個異常已經提高。

+0

我已經正式接受了Ben的答案,但是這個答案更爲正確,因爲背景管理者已經處理了這個複雜問題。 – Tommy

3

你的版本會盡快d is None運行dbc.close(),但如果沒有異常被引發。你需要一個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()不再處於捕獲mysql錯誤的try塊中,因爲它在我的版本中。是否在finally子句中放置另一個try塊?那很醜但是.. – 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)