前回はスクリプトの引数をデータに使う方法を紹介しました.
#!/usr/bin/python # -*- coding: utf-8 -*- import sys argv = sys.argv x = int(argv[1]) y = int(argv[2]) print x, '+', y, '=', print x + y
このスクリプトを保存したファイル名を sample.py とすれば,これは次のように実行します.
| Python スクリプトを引数を付けて実行する |
|---|
% ./sample.py 2 3[Enter]
2 + 3 = 5 |
しかし,このスクリプトを引数を付けずに実行すると,エラーになってしまいます.これはリスト argv に argv[1] という要素がないというエラーです.
| Python スクリプトを引数を付けずに実行する |
|---|
% ./sample.py[Enter]
File "./sample.py", line 8, in <module>
x = int(argv[1])
IndexError: list index out of range |
そこで今回は,このスクリプトを引数を付けずに実行したときに,不足するデータをキーボードから入力するよう求めるよう,スクリプトを変更します.
Python スクリプトの実行中にキーボードからデータの入力を行うには,raw_input() という関数が便利です.例えば,次の内容の name.py というスクリプトがあったとします.
#!/usr/bin/python
# -*- coding: utf-8 -*-
name = raw_input('May I your your name, please? ')
print 'Hi! ' + name + '. Nice to meet you.'
このスクリプトを実行すると,関数 raw_input() の (〜) の間に置いた引数の文字列をプロンプトとして出力して,データの入力を待ちます.入力されたデータは文字列として得られます.これを変数 name に格納しています.
| Python スクリプトを引数を付けて実行する |
|---|
% ./name.py[Enter] May I your your name, please? Kentaro[Enter] Hi! Kentaro. Nice to meet you. |
必要な数のデータが引数に与えられているかどうかは,引数の数を関数 len() を使って変数 sys.argv の要素数を調べればわかります.その結果,引数の数が2以外の場合に処理を変更するようにすれば,(引数の数の違いによる)エラーを避けることができます.このような判断には if を使います.引数を2個与えたときには,sys.argv の要素数は3(実際の引数の数より1多い)になりますから,それ以外の場合はメッセージを出力することにします.
#!/usr/bin/python # -*- coding: utf-8 -*- import sys argv = sys.argv argc = len(argv) # 引数の数 if argc == 3: # 引数の数が2個なら以下を実行する x = int(argv[1]) y = int(argv[2]) print x, '+', y, '=', print x + y else: # そうでなければ以下を実行する print u"引数が足りません"
if や else に続く行の行頭の空白 は必ず入れてください.emacs なら,[Tab] キーをタイプすれば自動的に必要な数の空白が入ります.このように行頭に空白を入れてプログラムの行をずらすことを,インデント(字下げ)といいます.インデントされた部分は,直前の if の条件によって実行されたりされなかったりします.このように Python では,このインデントによってプログラムの実行順序の制御を行います.
| Python スクリプトを引数の数を変えて実行する |
|---|
% ./sample.py[Enter] # 引数なし 引数が足りません % ./sample.py 2[Enter] # 引数1個 引数が足りません % ./sample.py 2 3[Enter] # 引数2個 2 + 3 = 5 % ./sample.py 2 3 4[Enter] # 引数3個 引数が足りません |
if および elif は,その右から : (コロン)までの間に置かれた条件にしたがって,プログラムの実行を制御します.条件が True(真=成立する)とき,それに続くインデントされた行が実行されます.else: に続くインデントされた行は,すべての条件が False(偽=成立しない)ときに実行されます.
| if 〜 elif 〜 else |
|---|
if 条件1: # 条件1が True(真)なら # この部分の処理が実行される elif 条件2: # 条件1が False(偽)のとき(成立しなかったとき)条件2が True(真)なら # この部分の処理が実行される elif 条件3: # 条件1・2が False(偽)のとき(成立しなかったとき)条件3が True(真)なら # この部分の処理が実行される ... else: # 上のいずれの条件も False(偽)のとき # この部分の処理が実行される # この部分はインデントされていないので条件にかかわり無く実行される |
この条件としては,次のようなものが使用できます.
| 条件 | |
|---|---|
| True | 常に真 |
| False | 常に偽 |
| 非 0 | 0 でない数値は常に True(真) |
| 0 | 数値の 0 は常に False(偽) |
| "abc" | 1 文字以上の長さの文字列は常に True(真) |
| "" | 文字数が 0 の文字列(空文字列)は常に False(偽) |
| (1,) | 空でないタプルは常に True(真) |
| () | 空のタプルは常に False(偽) |
| ["aaa"] | 空でないリストは常に True(真) |
| [] | 空のリストは常に False(偽) |
| {"aaa":1} | 空でないディクショナリは常に True(真) |
| {} | 空のディクショナリは常に False(偽) |
| x == y | x と y が等しいとき True(真) |
| x < y | x が y より小さいとき True(真) |
| x > y | x が y より大きいとき True(真) |
| x <= y | x が y より小さいか y と等しいとき True(真) |
| x >= y | x が y より大きいか y と等しいとき True(真) |
| x != y | x と y が等しくないとき True(真) |
| x and y | x と y がともに真のとき True(真) |
| x or y | x と y のどちらかが真のとき True(真) |
| not x | x が真のとき偽,偽のとき True(真) |
| x in dic | dic というディクショナリに x というキーが含まれていれば True(真) |
| x not in dic | not x in dic と同じ |
最初に,引数の数が2個かどうかを確かめていた部分を,2個以下かどうかに変更します.そうすると,else: 以降が処理されるのは引数の数が3個以上のときになるので,その場合に出すメッセージも変更します.
#!/usr/bin/python # -*- coding: utf-8 -*- import sys argv = sys.argv argc = len(argv) if argc <= 3: # 引数の数が2個以下なら以下を実行する(== を <= に変更) x = int(argv[1]) y = int(argv[2]) print x, '+', y, '=', print x + y else: # そうでなければ(3個以上)以下を実行する print u"引数が多すぎます"
そうすると,最初の if 以降の部分では,引数の数が 0,1,2 の三つの場合を処理する必要が出てきます.そこで,ここでもう一度 if (および elif)を使って場合分けをします.引数の数が 3 の場合の処理は以前と変わりません.ただし,二つ目の if によって実行される部分を,更にもう一段階インデントします.emacs であれば,そこで [Tab] をタイプします.
#!/usr/bin/python # -*- coding: utf-8 -*- import sys argv = sys.argv argc = len(argv) if argc <= 3: if argc == 3: # 引数の数が2個のとき x = int(argv[1]) y = int(argv[2]) print x, '+', y, '=', print x + y else: print u"引数が多すぎます"
引数が1個しかないときは,x にそれを使い,y は改めてキーボードから入力してもらうようにします.これを行うために,raw_input() を使います.入力された文字列ですから,これを int() を使って整数値に変換して,y に代入します.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
argv = sys.argv
argc = len(argv)
if argc <= 3:
if argc == 3:
x = int(argv[1])
y = int(argv[2])
elif argc == 2: # 引数の数が1個のとき
x = int(argv[1])
y = int(raw_input('y = ')) # キーボードからの入力.'y = ' はプロンプト
print x, '+', y, '=',
print x + y
else:
print u"引数が多すぎます"
引数が0個の場合は,x も y もキーボードから入力してもらうようにします.raw_input() を使って得た文字列を,int() により整数値に変換して,x および y に代入します.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
argv = sys.argv
argc = len(argv)
if argc <= 3:
if argc == 3:
x = int(argv[1])
y = int(argv[2])
elif argc == 2:
x = int(argv[1])
y = int(raw_input('y = '))
elif argc == 1: # 引数の数が0個のとき
x = int(raw_input('x = ')) # キーボードからの入力.'x = ' はプロンプト
y = int(raw_input('y = ')) # キーボードからの入力.'y = ' はプロンプト
print x, '+', y, '=',
print x + y
else:
print u"引数が多すぎます"
それでは,このスクリプトを実行してみましょう.引数の数を変えて実行して,期待通りの動作をするでしょうか.
| Python スクリプトを引数を変えながら実行する |
|---|
% ./sample.py[Enter] x = 10[Enter] y = 20[Enter] 10 + 20 = 30 % ./sample.py 10[Enter] y = 20[Enter] 10 + 20 = 30 % ./sample.py 10 20[Enter] 10 + 20 = 30 % ./sample.py 10 20 30[Enter] 引数が多すぎます |
raw_input() と input()実は Python には,raw_input() とは別に input() という便利な関数があります.これを使うと int() で整数に変換する必要もなくなります.ただし,これはキーボードからの入力を単なる文字列としてではなく,Python のプログラムとして実行してしまいます(正確には「評価する」と言います).したがって,そのことを考慮せずにこれを使うと非常に危険です.多くの場合,input() は使わないほうが無難です.なお,これは Python 2.x の機能であり,Python 3.x の input() は raw_input() と同じになります.>>> x = input('x を入れてください: ')[Enter] x を入れてください: 1+1[Enter] >>> x[Enter] 2 ← raw_input() なら '1+1' という文字列が入っている
コンピュータでは同じことを繰り返す処理が頻繁に現れます.Python の繰り返し処理を行う仕組みには,for 文や while 文があります.sample.py は二つの数値 x と y を入力して,その和を出力していますが,これをもとに,x 個の * からなる文字列の行を y 行出力することを考えてみます.以下に例を示します.
| x 個の * からなる文字列の行を y 行出力する(例) |
|---|
% ./sample.py 5 4[Enter]
*****
*****
*****
***** |
'*' という文字列を x 回繰り返して出力するには,'*' * x とします.したがって,sample.py を次のように変更します.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
argv = sys.argv
argc = len(argv)
if argc <= 3:
if argc == 3:
x = int(argv[1])
y = int(argv[2])
elif argc == 2:
x = int(argv[1])
y = int(raw_input('y = '))
elif argc == 1:
x = int(raw_input('x = '))
y = int(raw_input('y = '))
print '*' * x # '*' を x 回繰り返して出力する
else:
print u"引数が多すぎます"
これを実行すると,次のようになります.
| x 個の * からなる文字列の行を1行出力する |
|---|
% ./sample.py 5 4[Enter]
***** |
この出力を y 回繰り返せば,x 個の * が y 行出力されます.このような繰り返しには for 文が使います.for は,for の右に置いた変数に,in の右に置いた反復子(タプルやリストなど)の要素を一つ一つ代入して,次行以降のインデントされた行を繰り返します.
| for 〜 in |
|---|
for 変数 in 反復子: # 反復子の一つ一つの要素を変数に代入して # この部分の処理が実行される # この部分はインデントされていないので繰り返し終了後に実行される |
例えば,反復子として 'abc' という3文字の文字列を指定すれば,3回繰り返されます.print '*' * x の行の前に,for 〜 in による繰り返しを追加します.また,print '*' * x の行はインデントを一段追加します.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
argv = sys.argv
argc = len(argv)
if argc <= 3:
if argc == 3:
x = int(argv[1])
y = int(argv[2])
elif argc == 2:
x = int(argv[1])
y = int(raw_input('y = '))
elif argc == 1:
x = int(raw_input('x = '))
y = int(raw_input('y = '))
for i in 'abc': # 反復子として3文字の文字列を指定する
print '*' * x
else:
print u"引数が多すぎます"
これを実行すると,次のように文字列の長さ(文字数)だけ繰り返されます.
| x 個の * からなる文字列の行を1行出力する |
|---|
% ./sample.py 5 4[Enter]
*****
*****
***** |
したがって,反復子を y 文字の文字列にすれば,y 回繰り返すことができます.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
argv = sys.argv
argc = len(argv)
if argc <= 3:
if argc == 3:
x = int(argv[1])
y = int(argv[2])
elif argc == 2:
x = int(argv[1])
y = int(raw_input('y = '))
elif argc == 1:
x = int(raw_input('x = '))
y = int(raw_input('y = '))
for i in 'a' * y: # 反復子として y 文字の文字列を指定する
print '*' * x
else:
print u"引数が多すぎます"
これを実行すれば,期待したどおりの動作をするはずです.
| 反復子に文字列を指定した場合 |
|---|
% ./sample.py 5 4[Enter]
*****
*****
*****
***** |
反復子としては,文字列以外にタプルやリストも使えます.タプルの場合は (1,) *y,リストの場合は ['a'] * y で同じことができます.しかし,反復子には通常 range() か xrange() を使います.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
argv = sys.argv
argc = len(argv)
if argc <= 3:
if argc == 3:
x = int(argv[1])
y = int(argv[2])
elif argc == 2:
x = int(argv[1])
y = int(raw_input('y = '))
elif argc == 1:
x = int(raw_input('x = '))
y = int(raw_input('y = '))
for i in xrange(y): # 反復子として xrange(y) を指定する
print '*' * x
else:
print u"引数が多すぎます"
これを実行すれば,先ほどと同じ動作をするはずです.
| 反復子に xrange() を指定した場合 |
|---|
% ./sample.py 5 4[Enter]
*****
*****
*****
***** |
range() と xrange()range() は引数に指定した数の整数の要素をもつリストを生成します.range(5) は [0, 1, 2, 3, 4] というリストを生成します.range() は最大で三つの引数を指定できます.range(x, y, z) のように指定した場合,x は初期値として y を超えない最大の整数まで z ずつ増加させながら値を生成します.xrange() は range() と同様に反復子として使用しますが,単体ではリストを生成しません(その分メモリの節約します).なお,Python 3.x では range() は xrange() と同じになります.>>> range(5)[Enter] [0, 1, 2, 3, 4] >>> range(3,8,2)[Enter] [3, 5, 7] >>> xrange(8,3,-2)[Enter] xrange(8, 2, -2) # xrange() は 'xrange オブジェクト' を生成する >>> list(range(8,3,-2))[Enter] [8, 6, 4] # list() の引数に使うとリストが生成される
繰り返しを行う方法には,他に while があります.else: 以降は省略できます.
| while 〜 else |
|---|
while 条件: # 条件が True(真)の間(成立している限り), # この部分の処理が実行される else: # 条件が False(偽)になって繰り返しが終了したら, # この部分の処理が実行される # この部分はインデントされていないので繰り返し終了後に実行される |
次のような使い方をします.
| x 個の * からなる文字列の行を1行出力する |
|---|
>>> i = 0
>>> while i < 5:
... print i
... i += 1 # i に 1 を足す
... else:
... print u"おわり"
...
0
1
2
3
4
おわり |
次の (1) の作業を行ってください.完了したら,作成したスクリプトの内容をメールの本文にコピー&ペーストし,その後に (2) の内容を追加して tokoi@sys.wakayama-u.ac.jp に送ってください.メールの件名 (Subject) は shori1-13 にしてください.期限は次週の水曜日中までです.
幅 x 高さ y の箱を * で描く |
|---|
% ./sample.py 5 4[Enter] ***** * * * * ***** % ./sample.py 8 7[Enter] ******** * * * * * * * * * * ******** |