2012-07-27 2 views
4

Y at-il un avantage à écrire la fonction de générateur suivante en appelant simplement .fetchone() dans une boucle while? Si oui, quel serait cet avantage?Y a-t-il un avantage à une fonction de générateur d'accès à la base de données?

Merci.

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 
+0

probablement juste que son plus court de dire 'pour lire dans testf2(): doSomething' que de faire cette déclaration tout ... si son seul utilisé dans un endroit que vous n'êtes pas vraiment obtenir beaucoup, mais si vous faites cette requête à plusieurs reprises dans votre code, puis le mettre dans une fonction est conforme mieux SEC –

+0

l'emballage python pour mySQL pas suivre l'exemple du module 'sqlite3' et mettre en œuvre les curseurs comme eux-mêmes iterables, vous permettant de faire' pour meter_row dans sel_cur: '? – JAB

+0

@JAB Merci. C'était un bon point. – octopusgrabbus

Répondre

4

Nope. Fonctionnellement, ils sont les mêmes, mais il y a des avantages à l'encapsuler dans un générateur si vous voulez réutiliser le code. Par exemple, vous pouvez ajouter du code pour fermer la connexion/le curseur après la lecture dans le bloc générateur. Je vous recommande d'ajouter ceci à votre code ci-dessus pour que les curseurs soient fermés. Cela faciliterait la réutilisation, car il suffirait d'avoir la gestion des connexions à un seul endroit.

+0

Que se passe-t-il lorsqu'un objet générateur est collecté avant qu'il ne soit épuisé (par exemple, une exception augmente dans le corps de la boucle)? Ne serait-il pas préférable de placer le curseur dans un itérable qui implémente '__del __()'? –

+0

C'est une très bonne idée. – Wulfram

+0

@ AndréCaron http://docs.python.org/release/2.5/whatsnew/pep-342.html « L'ajout de la méthode' close() 'a un effet secondaire qui n'est pas évidente.' Close() ' est appelé quand un générateur est récupéré, donc cela signifie que le code du générateur a une dernière chance de fonctionner avant que le générateur ne soit détruit.Cette dernière chance signifie que les instructions 'try ... finally' dans les générateurs peuvent maintenant être garanties de fonctionner; la clause 'finally' aura désormais toujours une chance de fonctionner." Pas besoin de '__del __()'. – JAB

3

On dirait que j'avais raison, les curseurs mySQL sont iterable (https://stackoverflow.com/a/1808414/138772). Ainsi, vous pouvez tout faire à la place de la boucle while (mais j'aime l'idée de mettre le code de base de données l'accès à l'intérieur de la fonction de générateur, donc gardez cela):

for meter_row in sel_cur: 
    yield meter_row 

Notez également que vous ne voulez probablement pas cette finale yield None; L'exception StopIteration est utilisé pour indiquer l'épuisement de la production iterator, et est ce que for boucles utilisent comme drapeau pour arrêter de boucler, donc en incluant le yield None vous vous retrouvez avec cette None à la fin de votre sortie pour aucun gain réel.

0

L'utilisation d'un générateur vous donne une flexibilité supplémentaire pour utiliser les résultats dans le code existant. Par exemple, vous pouvez passer directement à une fonction csv.writerwriterows.

Questions connexes