Home > Tags > Python

Python

Python: ファイル読み込み時の例外の扱い例 - try、except、else、finallyブロック

ファイルのパスや名前のミス、パーミッションの権限が無い等が原因でファイルを読み込めない場合があります。そのような場合、すなわち例外が発生した際にそこで処理を中断して、発生した例外に合わせた処理ブロックにジャンプする構文が、try:~except Error:~構文です。

今回は、コマンドライン引数で英文テキストファイル名を指定し、スクリプト内でファイル内容を読み込み、単語数をカウントし出力するスクリプトを以って、オプションのelse、finallyブロックを含めた例外ブロックの扱いを確認します。
ただし、ここでの「単語」とは、1つの空白文字で区切られた文字列とします(簡単に)。

ソースコード

# -*- coding: UTF-8 -*-

import sys

script_name = sys.argv[0]
try:
    arg = sys.argv[1]
    f = open(arg, 'r')
except IndexError:
    print 'Usage: %s TEXTFILE' % script_name
except IOError:
    print '"%s" cannot be opened.' % arg
else:
    print arg, 'contains', len(f.read().split(' ')), 'words.'
    f.close()
finally:
    print 'n"%s" process end.' % script_name
    quit()
print 'Not reach this line.'

コードの説明

tryブロック

まず、例外を発生させる恐れのある行は、tryブロック内に書きます。

ここで発生しそうなのは、コマンドライン引数が格納されているリストへのアクセス部分であるsys.argv[1]です。[]演算子で存在しない要素を参照するエラー、もとい例外が発生する恐れがあります。

また、ファイルを開くopen(arg, 'r')も冒頭の理由で例外を発生させるかもしれません。

exceptブロック

exceptブロックは、tryブロックで例外が発生した場合にのみ実行されるブロックです。その為、例外が発生しない場合は実行されません。

発生する可能性のある例外のタイプ毎にexceptブロックを書けば、そのタイプ毎の例外への対処処理を書くことが出来ます。

except TYPE_AError:
    TYPE_AErrorが発生した際のとある処理...
except TYPE_BError:
    TYPE_BErrorが発生した際のとある処理...

elseブロック (オプション)

elseブロックは全てのexceptブロックの後に書きます(任意なので書かなくても構わない)。

elseブロックはtryブロックで例外が発生しなかった場合にのみ実行されるブロックです。今回は、ファイルの読み込みとクローズに使用しています。

finallyブロック (オプション)

finallyブロックはtryブロックで例外が発生するしないに関わらず実行されるブロックです(任意なので書かなくても構わない)。

実行結果

読み込むテキストファイルを以下のaLine.txtとします。
aLine.txt

Unless I set the standard where I am in any level, I'll be puzzled about what I should do from now on.

コマンドラインで適切な引数を与えた場合

$ python excp01.py aLine.txt
aLine.txt contains 22 words.

"excp01.py" process end.

存在しないファイル名を引数を与えた場合

$ python excp01.py texfile.tex
"texfile.tex" cannot be opened.

"excp01.py" process end.

コマンドライン引数を与えなかった場合

$ python excp01.py
Usage: excp01.py TEXTFILE

"excp01.py" process end.

例外オブジェクト名をpython処理系に聞いてみる

どんなメソッドや関数、演算子が、どのような例外を投げるのか予測が付かない場合があるかと思います。
そんな場合でもとりあえずスクリプトを実行してエラーを確認してみましょう。
SyntaxError: invalid syntax以外のエラーがある場合、例えば、

$ python excp01.py
Traceback (most recent call last):
  File "excp01.py", line 5, in 
    arg = sys.argv[1]
IndexError: list index out of range

のような場合は、最終行の行頭のIndexErrorが例外名となります。

何でも例外任せにしていいの?

計算量からみてあまり良いとは言えません。今プログラムのコマンドライン引数の確認を、
if len(sys.argv) != 2: ホニャララ
とすると整数の比較ですみますが、例外のキャッチに任せると、例外インスタンスを生成し送出するという、結構な計算量がかかります。ネットワーク接続やファイル読み書きなどのIOでは有効ですが、それ以外では積極的に使わないほうがいいかもしれません。

ドキュメント

Python: テキストファイルの行頭に行番号を追加

コマンドラインで指定されたテキストファイルの行頭に行番号を追加し、そのデータを新たなファイルに書き出すスクリプトです。

ソースコード

#!/usr/bin/python
# coding: UTF-8

import sys

argvs = sys.argv
argc = len(argvs)
if (argc != 3):
    print 'Usage: $ python %s target_file making_file' % argvs[0]
    quit()
f = open(argvs[1])
lines2 = f.readlines()
f.close()
nf = open(argvs[2], 'w')
i = 1
for line in lines2:
    nf.write('%3d: %s' % (i, line))
    i = i + 1
nf.close()

仮にこのソースコードをfile05a.pyというファイルで保存した場合、使用する際はプロンプトに以下のように打ち込みます。

実行結果

プロンプト

> python file05a.py file05a.py file05a-l.txt

この結果、生成されたファイルが下記になります。

file05a-l.txt

  1: #!/usr/bin/python
  2: # coding: UTF-8
  3:
  4: import sys
  5:
  6: argvs = sys.argv
  7: argc = len(argvs)
  8: if (argc != 3):
  9:     print 'Usage: $ python %s target_file making_file' % argvs[0]
 10:     quit()
 11: f = open(argvs[1])
 12: lines2 = f.readlines()
 13: f.close()
 14: nf = open(argvs[2], 'w')
 15: i = 1
 16: for line in lines2:
 17:     nf.write('%3d: %s' % (i, line))
 18:     i = i + 1
 19: nf.close()

Python: テキストファイルに書き込み - write()、writelines()メソッド

テキストファイルへの書き込み処理をFileオブジェクトの以下のメソッドを用いて書いてみます。

  • write() - 文字列を引数に取り、ファイルに書き込む。
  • writelines() - シーケンス型を引数に取り、ファイルに書き込む。

write() - 文字列を引数に取り、ファイルに書き込む

ソースコード

#!/usr/bin/python
# coding: UTF-8

# 書き込む文字列
str = """It is meaningless only to think my long further aims idly.
It is important to set my aims but at the same time I should confirm my present condition.
Unless I set the standard where I am in any level, I'll be puzzled about what I should do from now on."""

f = open('text.txt', 'w') # 書き込みモードで開く
f.write(str) # 引数の文字列をファイルに書き込む
f.close() # ファイルを閉じる

実行結果

text.txt

It is meaningless only to think my long further aims idly.
It is important to set my aims but at the same time I should confirm my present condition.
Unless I set the standard where I am in any level, I'll be puzzled about what I should do from now on.

writelines() - シーケンス型を引数に取り、ファイルに書き込む

ソースコード

#!/usr/bin/python
# coding: UTF-8

str = """It is meaningless only to think my long further aims idly.
It is important to set my aims but at the same time I should confirm my present condition.
Unless I set the standard where I am in any level, I'll be puzzled about what I should do from now on."""
strs = str.split('n') # 一行が一要素(文字列)のリスト

f = open('text.txt', 'w') # 書き込みモードで開く
f.writelines(strs) # シーケンスが引数。
f.close()

実行結果

text.txt

It is meaningless only to think my long further aims idly.It is important to set my aims but at the same time I should confirm my present condition.Unless I set the standard where I am in any level, I'll be puzzled about what I should do from now on.

書き込む際は、シーケンスの各要素の文字列を単に連結するだけです。間には改行も空白文字も含まれません。

そういえば、csv.writerオブジェクトを用いたCSVファイル書き込みにはlineterminatorオプション引数に、任意の連結文字列(言い方よくないね→行の終端文字)を代入できます。主に、環境に合わせた改行文字を代入するのに使います。→Python: CSVファイルに書き込み - csv.writerオブジェクト

リファレンス

Python: 二値の交換

ソート系のアルゴリズムを実装する際などに、配列の任意の2つの要素を交換する処理が必要な場合がありますので、以下にその手順の一例を示します。

ソースコード

# coding: UTF-8

a = [10, 20]
print '%d %d' % (a[0], a[1])
a[0], a[1] = a[1], a[0]
print '%d %d' % (a[0], a[1])

実行結果

10 20
20 10

何だかperlの多重代入を思い出します。

Python: 指定したパスのディレクトリ中のファイル一覧を出力

あるディレクトリから特定のファイルを検索したい場合、探索対象ディレクトリ内のファイルを全て取得する必要があります。今回は、引数にディレクトリを指すパスを指定することによって、そのディレクトリの内容を取得する関数を2つ示します。

ソースコード

# coding: Shift_JIS

import os # osモジュールのインポート

# os.listdir('パス')
# 指定したパス内の全てのファイルとディレクトリを要素とするリストを返す
files = os.listdir('C:\Python25\')

for file in files:
    print file

実行結果の一例

DLLs
Doc
include
Lib
libs
LICENSE.txt
lxml-wininst.log
NEWS.txt
PIL-wininst.log
pysqlite-wininst.log
pysqlite2-doc
python.exe
pythonw.exe
README.txt
Removelxml.exe
RemovePIL.exe
Removepysqlite.exe
Scripts
tcl
Tools
w9xpopen.exe

ワイルドカードでリスティング対象を指定

globモジュールのglob()関数の引数内にワイルドカード「*」を含めることが出来ます。これによって、より手軽に目的のファイルを探索することが出来ます。

ソースコード

# coding: Shift_JIS

import glob

# パス内の全ての"指定パス+ファイル名"と"指定パス+ディレクトリ名"を要素とするリストを返す
files = glob.glob('C:\Python25\*.*') # ワイルドカードが使用可能

for file in files:
    print file

os.listdir()と異なり、glob.glob()は取得したファイル文字列には先頭に探査ディレクトリ(引数)のパスが付いています。

実行結果の一例


C:Python25LICENSE.txt
C:Python25lxml-wininst.log
C:Python25NEWS.txt
C:Python25PIL-wininst.log
C:Python25pysqlite-wininst.log
C:Python25python.exe
C:Python25pythonw.exe
C:Python25README.txt
C:Python25Removelxml.exe
C:Python25RemovePIL.exe
C:Python25Removepysqlite.exe
C:Python25w9xpopen.exe

リファレンス

Page 1 of 712345...Last »

Home > Tags > Python

バックナンバー
最近のコメント
最近のトラックバック
メタ情報

Return to page top