2009-04-18 10 views
3

機能コード:Python Beginner: '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() 

私は試しでいることを理解しては..最後に、finallyブロックは必ず実行されます除きます。 上記のコードでは、最初のtryブロックに例外がある場合、2番目のtryブロックのfinallyを実行したくありません。私は間違って何をしていますか?

(注:のpython 2.4を使用して)

明確化:エラーが発生したときのMySQLdbは、自動的に接続を閉じた場合、私は知りません。私が上記のコードで直面している問題は、接続を確立する際にエラーが発生したとき(コードの最初のtryブロック)、finallyブロックのdbi.close()を呼び出すと "AttributeError: 'NoneType'オブジェクトに - finallyブロックで

# define at the start 
dbi = None 
sql = None 

、REPL人に

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

おかげ 必要に応じて、これは働いていた:...

ソリューションをDBIを参照して '閉じる' 属性」 ied。私は皆さんから何か新しいことを学びました。 (私は次の時間に私の質問をより明確にフレーズしようと思う:)。

+0

あなたは常に実行することが「最終的に」の目的であることに気づいていますか? –

+0

@Jeremy Cantrell: 私のクエリは非常にひどくフレーズでした。 はい、私は最終的に常に実行することを知っています。私の混乱は、コードのtryブロック(最終的にその一部である)が実行を開始した場合にのみ 'finally'が実行されるという前提から生じました。つまり、2つのtryブロック(上記)がある場合、プログラム 'flow'が2番目のtryブロックを入力/実行しないと、2番目のブロックのfinallyブロックは実行されないと考えました。 (あなたが私が何を言おうとしているのか理解したいと思っています)。 –

答えて

5

これらの接続を閉じる必要があるため、このケースでは最終的に使用したいと思います。

私は同じ方法で2つのtryブロックを持つべきではないという考えには同意しません。

デザインの欠陥は、同じ方法で接続を取得してクエリを実行することだと思います。私は2つを分離することをお勧めします。サービス・クラスまたはメソッドは、作業単位を知っています。接続を取得し、それをクエリを実行する別のクラスに渡し、完了したら接続を終了する必要があります。このようにして、クエリメソッドは発生した例外をスローして、接続を担当するクラスまたはメソッドにクリーンアップを残します。

+0

ええ、意味があります。 –

4

最後に使用しないでください。コードを常に実行したくない場合は、必要に応じて別のフロー制御構造を見つける必要があります。

この動作を実行する1つの方法は、 'finally'ブロック内のステートメントを 'try'ブロックの下部に移動することです。そうすれば、例外がスローされたときには実行されませんが、他のすべてのステートメント以降は実行されます。

EDIT:

さらなる議論した後、あなたのケースでは、あなたが実際には「最後に」を使用したいことが表示されます。私がお勧めするのは、接続を閉じる前に接続が既に閉じられているかどうかを確認することです。

+0

しかし、エラーが発生した場合はどうなりますか? MySQLdbはmysql接続を自動的に閉じますか? –

+0

@Samそれは問題ではないでしょうか? finallyブロックの唯一のコードなので、例外が発生したときに接続を閉じたくないかのように聞こえます。 –

+0

何か不明なエラーがあった場合に備えて、クエリが実行された後に接続を閉じる(1)必要があります(2)。 –

6

finally:の代わりにelse:を使用してください。ドキュメントのException Handling一部を参照してください。

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() 

..基本的に:

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] 
関連する問題