2009-04-18 2 views
3

Le code de fonction:Python Débutant: Comment empêcher l'exécution de 'finally'?

# Connect to the DB 
try: 
    dbi = MySQLdb.connect(host='localhost', \ 
          user='user', \ 
          passwd='pass', \ 
          db='dbname', \ 
          port=3309) 

    print "Connected to DB ..." 

except MySQLdb.Error, e: 
    apiErr = 2 
    apiErrMsg = "Error %d: %s" % (e.args[0], e.args[1]) 
    return 

    # To prevent try..finally bug in python2.4, 
    # one has to nest the "try: except:" part. 
try: 
    try: 
     sql = dbi.cursor() 
     sql.execute(""" 
     SELECT * 
     FROM table 
     WHERE idClient = %s 
     """, (key,)) 

     access = sql.fetchall() 

     # [some more code here]   

    except MySQLdb.Error, e: 
     apiErr = 2 
     apiErrMsg = "Error %d: %s" % (e.args[0], e.args[1]) 
     return 

finally: 
    sql.close() 
    dbi.close() 

Je comprends que, dans un essai .. sauf .. enfin, le bloc finally toujours exécuter. Dans le code ci-dessus, je ne veux pas que le bloc finally dans le second essai s'exécute s'il y a une exception dans le bloc try try. Qu'est-ce que je fais mal?

(Remarque: L'utilisation python 2.4)

Précisions: Je ne sais pas si MySQLdb ferme les connexions automatiquement lorsqu'une erreur se produit. Le problème auquel je fais face avec le code ci-dessus est, quand il y a une erreur dans l'établissement d'une connexion (le premier bloc try du code), appeler dbi.close() dans le bloc finally soulève "AttributeError: 'NoneType' objet n'a pas attribut «proche » en référence à DBI ...

Solution: Cela a fonctionné comme souhaité -

# define at the start 
dbi = None 
sql = None 

Dans le bloc enfin,

if sql is not None: 
    sql.close() 
if dbi is not None: 
    dbi.close() 

Merci à ceux qui rempl ied J'ai appris quelque chose de nouveau de vous tous. (Je vais essayer de formuler mes questions plus clairement la prochaine fois :).

+0

Vous êtes conscient que toujours exécuter est l'objectif de "enfin"? –

+0

@Jeremy Cantrell: Ma requête était assez mal formulée. Oui, je sais enfin toujours exécute. Ma confusion résultait de l'hypothèse qu'un 'finally' ne s'exécuterait que si le bloc try du code (dont le dernier fait partie) commençait à s'exécuter. C'est-à-dire, s'il y a 2 blocs d'essai (comme ci-dessus), je pensais que le dernier bloc ne s'exécuterait pas lorsque le programme 'flux' n'entrerait pas/n'exécuterait pas le second bloc try. (J'espère que vous avez compris ce que j'essaie de dire). –

Répondre

5

Je pense que dans ce cas vous voulez utiliser finalement, parce que vous voulez fermer ces connexions.

Je ne suis pas d'accord avec l'idée que vous devriez avoir deux blocs try dans la même méthode.

Je pense que la faille dans la conception est l'acquisition de la connexion et l'exécution de la requête dans la même méthode. Je recommanderais de séparer les deux. Une classe de service ou une méthode connaît l'unité de travail. Il doit acquérir la connexion, la transmettre à une autre classe qui exécute la requête et ferme la connexion quand c'est fait. De cette façon, la méthode de requête peut lever toute exception rencontrée et laisser le nettoyage à la classe ou à la méthode responsable de la connexion.

+0

Oui, c'est logique. –

4

Ne pas utiliser finalement. Si vous ne voulez pas que le code soit toujours exécuté, vous devriez trouver une autre structure de contrôle de flux qui répond à vos besoins. Une façon d'accomplir ce comportement est de déplacer les instructions dans votre bloc 'finally' au bas de votre bloc 'try'. De cette façon, ils ne seront pas exécutés lorsqu'une exception est levée mais sera exécutée, après toutes les autres instructions, sinon.

EDIT:

Après discussion, il semble que dans votre cas, vous ne voulez utiliser « enfin ». Ce que je recommande est de vérifier si votre connexion a déjà été fermée avant de tenter de le fermer.

+0

Mais que se passe-t-il lorsqu'une erreur survient? MySQLdb ferme-t-il automatiquement les connexions mysql si le programmeur ne l'a pas fait explicitement? –

+0

@Sam Il ne sera pas mais alors quel est le problème? Il semble que vous ne souhaitiez pas fermer la connexion lorsqu'une exception se produit car c'est le seul code de votre bloc finally. –

+0

Je souhaite que les connexions soient fermées (1) après l'exécution de la requête (2) en cas d'erreur inconnue. –

6

Utilisez else: au lieu de finally:. Voir la Exception Handling partie des docs:

The try ... except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception.

for arg in sys.argv[1:]: 
    try: 
     f = open(arg, 'r') 
    except IOError: 
     print 'cannot open', arg 
    else: 
     print arg, 'has', len(f.readlines()), 'lines' 
     f.close() 

..fondamentalement:

try: 
    [code that might error] 
except IOError: 
    [This code is only ran when IOError is raised] 
else: 
    [This code is only ran when NO exception is raised] 
finally: 
    [This code is always run, both if an exception is raised or not] 
Questions connexes