tuneoの日記: [Python]初期化時に例外が発生しうるオブジェクトをtryの中で初期化してfinallyで参照してはいけません 3
以下に示すのはよくありがちで、それでいて真似しちゃダメなコードです。
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で済むんですけど、他人のコードでこれを見るのは結構クるもんがありますね。
もしくは (スコア:1)
objectがnullかチェックしてcloseか(それも古いけど)
ですかねぇ
# 複数ブロックになるのがちょっとイヤなだけw
M-FalconSky (暑いか寒い)
Re:もしくは (スコア:1)
Pythonではopen()がファイルのオープンに失敗してIOErrorを発生させたときには「fはNoneが入ります」とかじゃなくて「fは一切オブジェクトと結合されない」ので、参照するとUnboundLocalErrorになります。だもんで
と書くのもいいかもしれません……俺の趣味ではありませんが。
Re:もしくは (スコア:1)
勘違いしていました。
前もってダミーの値で初期化しておいて、ということですね。