はじめに
このエントリはPythonを手っ取り早く利用できるためのもので
- 詳しい説明は抜きだ!
- とにかく最初は「使えた!」と思えることが大切である
- 理論はあとからちゃんと調べればよい
という考えで書いています。
実際には、自身が理解できておらず解説できない部分が多すぎるだけです。
ごごごめんなさい。
前編は以下です。
関数/メソッド
関数は「呼び出し側に値を返す一連の文」のことらしい。
メソッドは「クラス本体の中で定義された関数」のことらしい。
- 関数には引数を渡すことができる
- 関数を実行すると戻り値が返される
- pythonでは関数はどこかのモジュールやクラスに所属している
- モジュールで定義された関数は「関数」という
- クラスで定義された関数は「メソッド」という
Pythonでは一般的に以下の表現をしていることが多い(が、原典が見当たらず。。。)
- モジュール: 複数クラスや関数が記述される「ファイル」
- パッケージ: 複数モジュールを持つ「ディレクトリ」
- ライブラリ: 複数のパッケージやモジュールで構成される「集合体」
ここでは、よく使う関数のサンプル/使い方を紹介する。
関数/メソッドなど詳しい説明は その他の組み込み型 にもあります。(が、自分はあまり理解できていません)
関数の使い方
# ライブラリやモジュールを利用する場合
import ライブラリ名
import モジュール名
# 変数に関数の戻り値が代入される
変数 = モジュール.関数名(引数)
変数 = クラス.関数名(引数)
変数 = 変数.関数名(引数)
# 変数を操作したり、システムを操作したり、と、戻り値を使わないものもある
モジュール.関数名(引数)
クラス.関数名(引数)
変数.関数名(引数)
$ python -c "print('string')"
string
$ python -c "__builtins__.print('string')"
string
呼び出し側に値を返す一連の文 なので、使わないor意識しなくても返り値はある。
$ python -c "print(type(print('string')))"
string
<class 'NoneType'>
$ python -c "a=[2,3,4]; print(type(a.append('strings'))); print(a)"
<class 'NoneType'>
[2, 3, 4, 'strings']
組み込み関数
組み込みメソッド(builtin_function_or_method)は特定のクラスやインスタンスのメソッドではなく、引数をつけて関数を呼び出し、なんらかのデータ型を返す。
型変換
データ型を変換するための操作
int()
/ str()
/ bool()
/ list()
/ dict()
など
だいたい 前編 で解説したような使い方なので、省略します。
入出力
ファイルやキーボードから入出力するための操作
open()
/ input()
/ print()
など
だいたい 入出力の章(後述) で解説するような使い方なので、省略します。
数学
算術的な演算や抽出するための操作
min()
/ max()
/ sum()
/ pow()
など
リストを与えて算出結果を返したり、引数を与えて算出結果を返します。
$ python -c "a=[10, 20, 3]; print(min(a))"
3
$ python -c "a=[10, 20, 3]; print(max(a))"
20
$ python -c "a=[10, 20, 3]; print(sum(a))"
33
$ python -c "print(pow(3,3))"
27
オブジェクト
データ型に沿った情報を生成する操作
sorted()
/ reversed()
/ range()
/ enumerate()
/ slice()
など。
これらは、引数にとったオブジェクトはそのままで、新たにオブジェクトを生成する。
list()
は、ものすごくおおざっぱに考えて「引数をリストに変換する」と考えてしまってよい。
$ python -c "a=[3, 2, 5, 1, 4]; print(sorted(a))"
[1, 2, 3, 4, 5]
$ python -c "a=[3, 2, 5, 1, 4]; print(list(reversed(a)))"
[4, 1, 5, 2, 3]
$ python -c "print(list(range(0,5)))"
[0, 1, 2, 3, 4]
$ python -c "a=['a', 'b', 'c']; print(list(enumerate(a)))"
[(0, 'a'), (1, 'b'), (2, 'c')]
$ python -c "a=[1, 2, 3, 4, 5]; print(a[slice(2,4)])"
[3, 4]
変数に紐づくメソッド
リストの list_a.append(x)
/ list_a.clear()
など、変数に紐づいて操作するメソッドのこと。
append(x)もclear()も、正しくは ミュータブルなシーケンス型の演算 となっていますが このエントリの目的 からどんどん離れていってしまうので、そこまで解説しません。(自身も説明できるほど理解できてません)
一般的に使う変数は標準的なデータ型(=標準ライブラリの組み込み型)で生成されるので、標準ライブラリのメソッドではあるが、コードを記載する中ではよく利用されるのでセクションとして独立させている。
内容は 前編のデータ型 と一部重複してます。
文字列
count()
は文字列の文字数を数える
$ python -c "print('strings'.count('s'))"
2
find()
は何文字目に存在するかを調べる
$ python -c "print('strings'.find('t'))"
1
# 存在しない場合は -1 が返る
$ python -c "print('strings'.find('q'))"
-1
index()
は何文字目から開始するかを調べる
$ python -c "print('strings'.index('t'))"
1
# 存在しない場合は ValueError となる
$ python -c "print('strings'.index('q'))"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: substring not found
fortmat()
は、プレースホルダを指定して、変数をはめ込むことができる。
また、 書式指定ミニ言語仕様 という指定で任意の書式を指定できる。
$ python -c "print('Hello, {}'.format('Python'))"
Hello, Python
$ python -c "print('{a} {b}'.format(a='Good',b='morning'))"
Good morning
join()
は文字列配列を文字列にする。
split()
は文字列を文字列配列にする。
$ python -c "print(','.join(['one', 'two', 'three']))"
one,two,three
$ python -c "print('one,two,three'.split(','))"
['one', 'two', 'three']
upper()
は文字列をすべて大文字にする。
lower()
は文字列をすべて小文字にする。
$ python -c "print('Strings'.upper())"
STRINGS
$ python -c "print('Strings'.lower())"
strings
replace()
は文字列を置換する。
$ python -c "print('strings'.replace('str','th'))"
things
isXXX()
は文字列が特定の条件を満たすかをチェックして論理値を返す。
$ python -c "print('STRINGS'.isupper())"
True
$ python -c "print('Strings'.isupper())"
False
$ python -c "print('strings'.islower())"
True
$ python -c "print('Strings'.islower())"
False
# アルファベットと数字だけか?
$ python -c "print('strings123'.isalnum())"
True
$ python -c "print('strings\n'.isalnum())"
False
# 数値か?
$ python -c "print('strings123'.isdigit())"
False
$ python -c "print('1234567'.isdigit())"
True
数値の取り扱いは難しいので、以下参照
- isdigit(): 全ての文字が数字
- isdecimal(): 全ての文字が十進数字
- isnumeric(): 全ての文字が数を表す文字
リスト
index()
は、指定した要素が最初に出現する添え字番号を返す。
count()
は、指定した要素が出現する回数を返す。
list_a = ['1', '2', '4', '2']
# indexはその要素が最初に出現する添え字番号を返す
print(list_a.index('2'))
# countはその要素が出現する回数を返す
print(list_a.count('2'))
1
2
append()
/ insert()
/ extend()
は、既存の配列に新に要素を追加する。
list_a = ['1', '2', '4', '2']
# appendは配列の最後にその要素を加える
list_a.append('5')
print(list_a)
# insertは配列の指定した添え字の箇所にその要素を加える
list_a.insert(0,'10')
print(list_a)
# extendは配列に新たな配列を追加(拡張)する
list_a.extend(['str01','str02'])
print(list_a)
['1', '2', '4', '2', '5']
['10', '1', '2', '4', '2', '5']
['10', '1', '2', '4', '2', '5', 'str01', 'str02']
pop()
/ remove()
/ clear()
は、既存の配列の要素を削除する。
list_a = ['1', '2', '4', '2']
# 配列のうち、指定した添え字の要素がpopされる
# popした対象が返り値になる
print(list_a.pop(0))
print(list_a)
# -1 は配列の最後を指し示す
print(list_a.pop(-1))
print(list_a)
# 配列のうち、最初の'2'が削除される
# removeした対象は返り値にならない
print(list_a.remove('2'))
print(list_a)
# clearはすべての要素を削除する
list_a.clear()
print(list_a)
1
['2', '4', '2']
2
['2', '4']
None
['4']
[]
配列は、文字列変数のように代入して利用しようとすると、想定した動作とならない場合がある。これは、配列を代入しても、同じオブジェクトを参照してしまうためである。
list_a = ['1', '2', '4', '2']
# list_aをlist_bに代入した場合
list_b = list_a
# list_aをpopすると
list_a.pop(0)
# list_aの最初の要素は削除されるが
print(list_a)
# list_bの最初の要素も削除されてしまう
print(list_b)
# 理由はlist_bがlist_aと同一のオブジェクトになっているからである
# idは対象オブジェクトの固有番号(オブジェクトID)を返す関数
print(id(list_a),id(list_b))
['2', '4', '2']
['2', '4', '2']
1204481676864 1204481676864
このように配列を複製して利用したい場合は copy()
を利用する。
list_a = ['1', '2', '4', '2']
# list_aをlist_bにコピーした場合
list_b = list_a.copy()
# list_aをpopすると
list_a.pop(0)
# list_aの最初の要素は削除される
print(list_a)
# list_bはもとのままになる
print(list_b)
# 理由はcopyした場合はlist_bがlist_aと別のオブジェクトになっているからである
print(id(list_a),id(list_b))
['2', '4', '2']
['1', '2', '4', '2']
2836583929408 2836584006592
sorted()
とreversed()
は配列の順序を変える。
似た関数にsort()
とreverse()
があるが、これらの違いは「配列そのものを操作する」か「新たに配列を生成する」か、の違いである。
list_a = ['3', '2', '4', '2']
# 整列した配列を生成する
list_b = sorted(list_a)
print(list_b)
# list_aとlist_bは別のオブジェクトである
# 配列そのものを整列する
list_a.sort()
print(list_a)
print(id(list_a),id(list_b))
['2', '2', '3', '4']
['2', '2', '3', '4']
2501765224000 2501765562176
reversed()
の場合は 前述のオブジェクト のとおり、iteratorとして返ってくるので、listすれば配列として取り扱える。
list_a = ['3', '2', '4', '2']
# 逆列したiteratorを生成する
list_b = reversed(list_a)
print(list_b)
# iteratorなのでlistでキャストすればlistとして取り扱える
print(list(list_b))
# 配列そのものを逆列にする
list_a.reverse()
print(list_a)
# list_aとlist_bは別のオブジェクトである
print(id(list_a),id(list_b))
<list_reverseiterator object at 0x000001B420F6F820>
['2', '4', '2', '3']
['2', '4', '2', '3']
1873158592064 1873158797344
辞書
dict_a = {
'key11': 1,
'key12': 'moji',
'key13': False,
}
dict_b = {
'key21': 33,
'key22': 'string',
'key23': True,
'key12': 'new moji'
}
# dict_aのオブジェクトIDを表示
print(id(dict_a))
# updateは既存の辞書に、別の辞書を加える
dict_a.update(dict_b)
print(dict_a)
print(id(dict_a))
# | は新たな辞書を生成する操作である
dict_a = dict_a|dict_b
print(dict_a)
print(id(dict_a))
2017211977088
{'key11': 1, 'key12': 'new moji', 'key13': False, 'key21': 33, 'key22': 'string', 'key23': True}
2017211977088
{'key11': 1, 'key12': 'new moji', 'key13': False, 'key21': 33, 'key22': 'string', 'key23': True}
2017212041664
dict_a = {
'key11': 1,
'key12': 'moji',
'key13': False,
}
# キーがkey11の値を取得
print(dict_a.get('key11'))
# キーが存在しない場合はNoneが返る
print(dict_a.get('undef'))
# キーがkey11の値を取り出す(もとの辞書からは削除される)
print(dict_a.pop('key12'))
print(dict_a)
# キーが存在しない場合はKeyErrorになる
print(dict_a.pop('undef'))
print(dict_a)
1
None
moji
{'key11': 1, 'key13': False}
Traceback (most recent call last):
File "C:\Users\basha\tmp\python\sample.py", line 17, in <module>
print(dict_a.pop('undef'))
KeyError: 'undef'
dict_a = {
'key11': 1,
'key12': 'moji',
'key13': False,
}
# itemsはキーと値のタプルのビュー(リストのようなもの)が返る
print(dict_a.items())
# keysはキーのみのビュー(リストのようなもの)が返る
print(dict_a.keys())
# valuesは値のみのビュー(リストのようなもの)が返る
print(dict_a.values())
dict_items([('key11', 1), ('key12', 'moji'), ('key13', False)])
dict_keys(['key11', 'key12', 'key13'])
dict_values([1, 'moji', False])
メソッドチェーン
データ型に対してメソッドを呼んだとき、その返り値に対してメソッドを呼ぶことができる。ただし、呼べるメソッドはデータ型に対応したものである必要がある。
str_a='Strings'
# str_bはstr_aがすべて大文字になった文字列である
str_b = str_a.upper()
print(str_b)
# str_cはstr_b(=str_aがすべて大文字になった文字列)を
# Sをsに置き換えた文字列である
str_c = str_b.replace('S','s')
print(str_c)
# str_dはstr_aがすべて大文字になった文字列を、Sをsに置き換えた文字列である
str_d = str_a.upper().replace('S','s')
print(str_d)
# 左側から順番に操作していくので、これでは想定する結果が得られない
str_e = str_a.replace('S','s').upper()
print(str_e)
STRINGS
sTRINGs
sTRINGs
STRINGS
また、チェーンする数が多くなったり、関数名や引数が長い場合は、可読性が下がるので、複数行に分けて記述することができる。
Pythonではカッコで括られた部分は文字の途中でなければ改行できるので、以下のように記述することができる。
str_a='Strings'
# 全体をカッコで括るパターン
str_new = ( str_a
.upper()
.replace('S','s')
)
print(str_new)
# メソッドのカッコで改行するパターン
str_new = str_a.upper(
).replace(
'S',
's'
)
print(str_new)
sTRINGs
sTRINGs
適用させるメソッドのデータ型が合致すれば、メソッドチェーン内で型が変わっていっても問題ない。
$ python -c "print(','.join(['one', 'two', 'three']).upper().split('T'))"
['ONE,', 'WO,', 'HREE']
ライブラリ/パッケージ/モジュール
Pythonには標準ライブラリというさまざまな機能を提供するパッケージが存在している。「テキスト処理サービス」や「汎用オペレーティングシステムサービス」などに分類される。
ライブラリ、パッケージ、モジュール、クラス、関数、などの用語が出てくるが、包含関係としては以下のように覚えておけばよい。
- パッケージ(複数モジュール(ファイル)の集合=フォルダ)
- モジュール(クラスや関数をファイルにしたもの)
- クラス・関数
同一のものをライブラリと呼んだり、パッケージと呼んだりするが、あまり明示されていないようなので、意図が通じれば気にしなくてよいと思います。(というか、自身がよく理解できていません)
ライブラリを利用する場合は import xxx
でどのライブラリを利用するかを指定する必要があります。
以下よく利用される標準ライブラリとその使い方を解説します。
os
$ python -c "import os; print(os.environ)"
environ({'ACLOCAL_PATH': '/mingw64/share/aclocal:/usr/share/aclocal',
(~環境変数が表示される~)
$ python -c "import os; print(os.mkdir('sample-dir'))"
None
os.system()
OSコマンドが実行できる関数ですが subprocess
モジュール の利用が推奨されています。
subprocess
基本的な使い方は以下のとおり。
- capture_output: 標準出力と標準エラー出力を返り値に含める
- text: 標準出力と標準エラー出力を文字列にする(デフォルトFalseの場合はバイト列になる)
- encoding: 標準出力と標準エラー出力の文字列エンコーディングを指定する
コマンドの実行結果は返り値の stdout
に含まれている。
import subprocess
# 実行したいコマンドを配列に格納する
cmd = ["ls","-hs","*.py"]
cp = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8")
print("stdout:", cp.stdout)
# 文字列として指定する場合は shell=True とする
cmd = "ls -hs *.py"
cp = subprocess.run(cmd, shell=True, capture_output=True, text=True, encoding="utf-8")
print("stdout:", cp.stdout)
stdout: 1.0K sample.py
stdout: 1.0K sample.py
コマンドの実行結果で標準エラー出力がある場合は stderr
に含まれている。
コマンドの実行結果が正常終了でない場合は check=True
とすることでPython内で例外として取り扱うことができるようになる。
import subprocess
# 標準エラー出力は stderr に格納される
cmd = ["ls", "wrong-filename"]
cp = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8")
print("stdout:", cp.stdout)
print("stderr:", cp.stderr)
# check=Trueとするとエラー時にPythonの例外を発生させる
cmd = ["ls", "wrong-filename"]
cp = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", check=True)
stdout:
stderr: ls: cannot access 'wrong-filename': No such file or directory
Traceback (most recent call last):
File "C:\Users\basha\tmp\python\sample.py", line 11, in <module>
cp = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", check=True)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\subprocess.py", line
526, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['ls', 'wrong-filename']' returned non-zero exit status 2.
re
re.match
/ re.search
/ re.fullmatch
はいずれも、文字列を正規表現でチェックする。
3つの違いは search() vs. match() のとおり。
re.match() checks for a match only at the beginning of the string
re.search() checks for a match anywhere in the string (this is what Perl does by default)
re.fullmatch() checks for entire string to be a match
-
re.match()
「対象文字列の先頭」でマッチするかをチェックする -
re.search()
「対象文字列のどこか」でマッチするかをチェックする -
re.fullmatch
「対象文字列のすべて」でマッチするかをチェックする
import re
# 先頭がマッチするかチェックするのが match
print(re.match("abc", "abcdef"))
print(re.match("bcd", "abcdef"))
# 先頭以外でもマッチするかチェックするのが search
print(re.search("cd", "abcdef"))
print(re.search("^c", "abcdef"))
# 全体がマッチするかチェックするのが fullmatch
print(re.fullmatch("p.*n", "python"))
print(re.fullmatch("r.*n", "python"))
マッチしていれば Matchオブジェクト
というものが返る。
マッチしていなければ None
が返る。
<re.Match object; span=(0, 3), match='abc'>
None
<re.Match object; span=(2, 4), match='cd'>
None
<re.Match object; span=(0, 6), match='python'>
None
Matchオブジェクトではなく、文字列として返したい場合は findall
を利用する。
findall
はマッチした要素が文字列の配列として返ってくる
r'[文字列]'
は raw文字列というもので、エスケープシーケンスを含む特殊文字を特殊文字ではなく、そのままの文字列として解釈させる指定ができる。re
を利用するときによく利用される。
import re
# \b は単語の区切りという意味の正規表現
print(re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest'))
# グループ化すると、グループ化した要素だけがタプルで返ってくる
print(re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10'))
# re.IGNORECASE を指定すると、大文字小文字が無視される
print(re.findall(r'python', 'PYTHON Python python'))
print(re.findall(r'python', 'PYTHON Python python', re.IGNORECASE))
['foot', 'fell', 'fastest']
[('width', '20'), ('height', '10')]
['python']
['PYTHON', 'Python', 'python']
findall
はマッチした部分を文字列配列として取り出すが、マッチした部分で分割するには split
を利用する。
import re
# \s はホワイトスペース(空白、タブ、改ページ、改行など)という意味の正規表現
print(re.split(r'\s', 'which foot or hand fell fastest'))
# 3つめの引数は maxsplit で、最大何回区切るか、を指定することができる
print(re.split(r',', 'Words, words, words.'))
print(re.split(r',', 'Words, words, words.', 1))
['which', 'foot', 'or', 'hand', 'fell', 'fastest']
['Words', ' words', ' words.']
['Words', ' words, words.']
正規表現でマッチした部分を別の文字列で置き換える場合には sub
を利用する。
import re
# 置換したい正規表現, 置換先の文字列, 置換元の文字列 の順に指定する
print(re.sub(r',\s', ' / ', 'apple, banana, carot'))
# 4つめの引数は count で、最大何回置換するか、を指定することができる
print(re.sub(r',\s', ' / ', 'apple, banana, carot', 1))
apple / banana / carot
apple / banana, carot
入出力
これまでのサンプルでは、コードに記載された情報だけを利用して処理をしていた。
(たとえば、コード内の決め打ちの変数を print
するなど)
ここでは、コードに記載された情報以外の情報をプログラムに引き渡すことで、情報の入出力ができる方法について解説する。
コマンドライン引数
これまでは python [ファイル名]
という形式でプログラムを実行していたが、ファイル名の後に引数をつけることで、その引数をプログラム内で利用することができる。
キーボードからの入力
Pythonスクリプトへはキーボード入力を受け付けてコードの動作に反映させることができる。
moji = input("input strings: ")
print("入力文字: " + moji)
input strings: ← ここで文字を入力してEnterを押す
「おはよう」と入力すると、入力された文字をそのまま出力する
input strings: おはよう
入力文字: おはよう
ターミナルへの出力
print
はターミナルへ文字を出力していたが、文字列を出力する方法が何通りかある。
str_morning = "おはよう"
str_noon = "こんにちは"
str_evening = "こんばんは"
# 文字列として連結したものを表示させる
print(str_morning + str_noon + str_evening)
# 複数の文字列をカンマで区切るとスペースで連結される
print(str_morning, str_noon, str_evening)
# 連結する文字をsepで変更できる(デフォルトはスペース)
print(str_morning, str_noon, str_evening, sep='#')
# endで行末文字を指定できる(デフォルトは改行コード)
print(str_morning, str_noon, str_evening, end='#EOL\n')
# 変数名を直接指定することもできる
print(f'Morning: {str_morning}')
# {}を利用したフォーマット
print('Morning: {morning}, Noon: {noon}'.format(morning=str_morning,noon=str_noon))
おはようこんにちはこんばんは
おはよう こんにちは こんばんは
おはよう#こんにちは#こんばんは
おはよう こんにちは こんばんは#EOL
Morning: おはよう
Morning: おはよう, Noon: こんにちは
ファイルからの入力
以下のようなファイルをあらかじめ作成しておく
hostname01.example.com
hostname02.example.com
hostname03.example.com
file = 'hosts.txt'
# 読み込みモードのときは mode='r' とするが、省略可である
with open(file) as f:
# ファイル全体をひとつの変数として取り込む場合はread()を使う
stream = f.read()
print(stream)
# いちど読み込んだファイルを再度読み込む場合には、再度openから始める必要がある
# 読み込む場所を移動するseekもありますが、ここでは触れません
with open(file) as f:
# ファイル全体をリストとして取り込む場合はreadlines()を使う
stream = f.readlines()
print(stream)
server01.example.com
server02.example.com
server03.example.com
['server01.example.com\n', 'server02.example.com\n', 'server03.example.com\n']
ファイルへの出力
file = 'output.txt'
# 書き込みモードのときは mode='w' とする
with open(file, mode='w') as f:
# ひとつの変数を書き込む場合はwrite()を使う
host_body = 'hostname01.example.com\n'
host_body += 'hostname02.example.com\n'
host_body += 'hostname03.example.com\n'
f.write(host_body)
# 追記モードのときは mode='a' とする
with open(file, mode='a') as f:
# リストを書き込む場合はwritelines()を使う
host_list = ['hostname01.example.com\n',
'hostname02.example.com\n',
'hostname03.example.com\n',
]
f.writelines(host_list)
これを実行してもターミナルには何も表示されない(print文などで標準出力へ出力していないため)が、 output.txt
というファイルが生成されている。
$ cat output.txt
hostname01.example.com
hostname02.example.com
hostname03.example.com
hostname01.example.com
hostname02.example.com
hostname03.example.com
自動的に改行を付与するオプションは無いので、リストを改行付きで書き込みたい場合は、以下のように工夫する必要がある。
file = 'output.txt'
with open(file, mode='w') as f:
host_list = ['hostname01.example.com',
'hostname02.example.com',
'hostname03.example.com',
]
# リストを改行コードでjoinした文字列をwrite()で書き込む
f.write('\n'.join(host_list) + '\n')
# リストの各要素に改行コードを追加したリストをwritelines()で書き込む
f.writelines(host + '\n' for host in host_list)
練習問題
"input strings: " というプロンプトでキーボード入力を待ち受けて、入力された文字列をファイル(output.txtとする)に追記して終了する処理
file = 'output.txt'
prompt = "input strings: "
moji = input(prompt)
buf = prompt + moji + '\n'
with open(file, mode='a') as f:
f.writelines(buf)
$ python ./sample.py
input strings: sample strings
^^^^^^^^^^^^^^
↑の部分がキーボード入力
$ python ./sample.py
input strings: 30
^^
↑の部分がキーボード入力
$ cat output.txt
input strings: sample strings
input strings: 30
例外処理
前編の型変換のセクションで、変換できないものがエラーになると記載した。このエラーが「例外」のことで、そのままでは処理が途中で強制終了ししてしまいます。
moji = 'sample'
print(int(moji))
print('例外発生後の処理')
Traceback (most recent call last):
File "C:\Users\basha\tmp\python\sample.py", line 2, in <module>
print(int(moji))
ValueError: invalid literal for int() with base 10: 'sample'
このような場合に、「例外処理」として発生したエラーの内容に応じて後続の処理を実施することができます。
例外の種類
実行時に発生しやすい例外として以下のものがある。
例外 | 意味 |
---|---|
TypeError |
型が違うことにより処理することができない場合 |
ValueError |
型は問題ないが処理することができない場合 |
IndexError |
(リストやタプルなどで)存在しない添え字にアクセスしようとした場合 |
KeyError |
(辞書型で)存在しないキーにアクセスしようとした場合 |
ZeroDivisionError |
ゼロ除算が実行された場合 |
このほかOverflowError
もありますが、整数では発生しないため、このエントリでは取り上げません。
TypeError
以下の場合、文字列型と整数型を結合しようとしているのでエラーになります。
$ python -c "a='str'+10"
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
ValueError
以下の場合 int
による型変換でstr
という文字列を変換しようとしているのでエラーになります。文字列の100
を変換する場合にはエラーが発生しません。
$ python -c "a=int('str')"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'str'
IndexError
以下の場合 range(3)
に対する添え字でのアクセスは0~2のみが許可されるためエラーになります。1番目にアクセスするのであればエラーが発生しません。
$ python -c "a=range(3)[99]"
Traceback (most recent call last):
File "<string>", line 1, in <module>
IndexError: range object index out of range
KeyError
以下の場合はキーが key1
しか存在しないので、キーとして key
を参照しているためエラーになります。キーとして key1
を参照するのであればエラーが発生しません。
$ python -c "a={'key1': 'value1'}; v=a['key']"
Traceback (most recent call last):
File "<string>", line 1, in <module>
KeyError: 'key'
ZeroDivisionError
以下の場合はゼロで除算しているためエラーになります。
$ python -c "a=2/0"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ZeroDivisionError: division by zero
例外のキャッチ
例外が発生しそうな処理の記載箇所はあらかじめtry
に記載しておき、例外が発生したらexcept
の処理を実行することができます。例外の発生を検出することは、例外をキャッチする、と言ったりもします。
moji = 'sample'
try:
print(int(moji))
except:
print('例外が発生')
print('例外発生後の処理')
例外が発生
例外発生後の処理
上記の例では except:
と記載していますが、この記載ではどのような種類の例外もキャッチして処理を実行します。
例外の種類ごとに異なる処理を実行したい場合には、特定の例外だけをキャッチするように記載します。
moji = input("input number: ")
list_a = [10, 20, 30]
try:
print('入力された数字: '+moji)
print('リストの' + moji +'番目の値: '+str(list_a[int(moji)]))
except ValueError:
print('ValueErrorが発生')
except IndexError:
print('IndexErrorが発生')
except:
print('不明な例外が発生')
$ python ./sample.py
input number: 1
入力された数字: 1
リストの1番目の値: 20
$ python ./sample.py
input number: sample
入力された数字: sample
ValueErrorが発生
$ python ./sample.py
input number: 100
入力された数字: 100
IndexErrorが発生
練習問題
前述の練習問題を改修して、書き出すファイルには数値のみ出力し、キーボード入力された文字を整数として取り扱い、ファイルの最終行の数値と入力された数値を合算してファイルに追記する。ただし、キーボード入力された文字が整数として取り扱えなかった場合はエラーメッセージを出力して処理を終了する。
file = 'output.txt'
# output.txtの最終行を読み取り整数変換する
# 読み取った数値を prev に代入する
# ファイルがない場合は例外処理として prev に0を代入する
try:
with open(file) as f:
stream = f.readlines()
prev = int(stream[-1])
except:
prev = 0
# キーボード入力を受け付けて整数変換する
# 整数変換で例外となった場合はメッセージを出力して処理を終了させる
try:
num = int(input('input strings: '))
print('OK')
except:
print('NG: not a number')
exit()
# 処理が進んだ場合は、最初に読み取った数値とキーボード入力の数値を合算してファイルに出力する
with open(file, mode='a') as f:
f.writelines(str(prev+num)+'\n')
$ rm output.txt
$ python ./sample.py
input strings: sample
NG: not a number
$ python ./sample.py
input strings: 10
OK
$ cat output.txt
10
$ python ./sample.py
input strings: 2
OK
$ cat output.txt
10
12
さいごに
ユーザ定義関数とか、外部ライブラリ&virtualenvとかもやりたかったのですが、ここまでが限界でした。
前編とあわせてここまで手を動かしてやってみれば、Pythonでの簡単な文字列処理や数値集計など、ある程度やりたいことはできるんじゃないか~、と思います。