パスワードを忘れた? アカウント作成
6822806 journal
日記

tuneoの日記: [Python]初期化時に例外が発生しうるオブジェクトをtryの中で初期化してfinallyで参照してはいけません 3

日記 by tuneo

以下に示すのはよくありがちで、それでいて真似しちゃダメなコードです。

try:
  f = open(filename)
  for l in f:
    print l,
finally:
  f.close()

このコード、実行時にファイルのオープンに失敗するとf.close()で「UnboundLocalError: local variable 'f' referenced before assignment」と例外が発生するんですよ。「ローカル変数fが代入される前に参照されている」ってことですね。※トップレベル(関数の内部とかじゃない)のコードでやると「NameError: name 'f' is not defined.」になります。

Pythonでは「関数が値を返しつつ例外を発生させる」ということは不可能なので、例外が発生したら値は帰ってきません。式「open(filename)」を評価してopen()の内部でファイルのオープンに失敗し、IOError例外が発生した時点ではopen()は何も値を返していないので、名前fに結合されたオブジェクトは存在しません。上のコードではexceptブロックでIOErrorを捕捉していないため、例外が発生するとfに何のオブジェクトも結合されないまま直ちにfinallyの実行が始まるわけですが、それなのにf.close()なんてメソッドを呼び出そうとしたら、そりゃ文句言われて当然です。

つまり上のコードはこう書け、ということですね。

try:
  f = open(filename)
except IOError:
  print 'Failed to open file.'
  sys.exit(1)
 
try:
  for l in f:
    print l,
finally:
  f.close()

自分のコードだと何やってんだ俺のバカorzで済むんですけど、他人のコードでこれを見るのは結構クるもんがありますね。

この議論は、tuneo (2938)によって ログインユーザだけとして作成されたが、今となっては 新たにコメントを付けることはできません。
typodupeerror

犯人はmoriwaka -- Anonymous Coward

読み込み中...