モンキーPython (Python3対応): 第3回 分岐・繰り返しなどとファイル操作 前編

この文書は、Linux magazine 2005年1月号〜3月号に掲載された連載の草稿を、(株)アスキーLinux magazine編集部の許可を得て公開するものです。校正前の原稿なので読みづらいところもあるかと思います。不明な点などありましたらコメントをお送りください。


プログラムは、ソースコードの上から順に実行するだけでなく、ときには条件によって実行しなかったり、繰り返したりする必要があります。今回は、そのような手法について学習しましょう。また、前回のお絵かきプログラムのデータをファイルに保存できるように改造してみます。

今回はかなり文法中心の内容と, 駆け足の説明ですが、頑張っていきましょう。

今回の目次:

  1. 実行する順序を変える
    • if文 "もし〜ならば"
    • 関係を調べる
    • 真偽値
    • if文ふたたび
    • while文 "〜の間"
    • for文 "〜のそれぞれについて"
    • break文 "中断"
    • continue文 "次へ進む"

前回までのプログラムは、ソースコード上の命令 (文) は、上から順番に実行されるものばかりでした。ユーザがマウスをクリックしたりしたときに別のメソッドを呼び出したりすることもありましたが、私たちが書くソースコード (スクリプト) のなかでは、やはり上から下に実行されるだけでした。

@ 実行する順序を変える

データの内容やユーザの操作によっては、単純に上から順に実行するだけではやりたいことを実現できないことがあります。状況によっては、ある部分は実行してある部分は実行しない、あるいはプログラムのうち一定の範囲を何度か繰り返して実行するようにしたい、ということがあります。

このようなとき、Pythonでは、if文while文for文を使います。いずれも、これらの文を実行するときに指定する条件が成立しているかどうかを確認して、成立しているときにだけ付随する文を実行したり、繰り返したりします。

このほかにも便利な(短く書ける)書き方もありますが、まずは以下のものを覚えるだけで事足ります。

■if文 "もし〜ならば"

if文は、文の固まりを、条件次第で、あるときには実行してあるときには実行しないようにします。文法は次のとおりです。

if 式:
    文
    文
    文...

まずifの直後に式を書きます。この式を条件式といいます。スクリプトの実行の流れが if文のところにきたときにこの式が計算され、その計算結果が(後述します。)のとき、「:」の次に続く文が実行されます。

実行するかどうかの対象となる文は、字下げして書きます。字下げしている範囲がひと塊として扱われます。この固まりでは、新しい変数のスコープは導入されません。

次のスクリプトは、ごく単純なもので、ユーザに数を入力するように求め、入力結果が5より大きいときのみ画面に文字列を出力します。5以下のときは何もせず終了します。

03-01.py

Python
[RAW]
  1. # -*- coding:utf-8 -*-
  2. x = int( input("数字>>> ") )
  3. if x > 5:
  4. print("入力された数字は5より大きい。")

例えば6を入力したときの実行結果は次のようになります。

$ python3 03-01.py    
数字>>> 6
入力された数字は5より大きい。

input()は、引数の文字列を画面に表示した上で、ユーザからの入力を待ちます。ユーザが何か入力してEnterキーを打つと、入力した文字列が戻り値となります。

■関係を調べる

条件式では、二つの値が一致しているか、あるいは大小関係などを調べたいです。すでに示したサンプルで、変数x(の指すオブジェクト)が数値の5より大きいか調べました。

二つの値(オブジェクト)が一致しているかは「==」で、大きいかは「>」で調べることができます。このような記号を関係演算子といいます。その一覧は表1です。and, orの計算結果はTrue, Falseではありません。これが役立つところもありますが、今は気にしなくてもいいです。

表1 関係演算子
記法 計算結果がTrueになるとき
x == y xとyが一致している
x != y xとyが一致していない
x < y xがyより小さい
x <= y xがyと同じか小さい
x > y xがyより大きい
x >= y xがyと同じか大きい
x in y xがyに含まれる
x and y xかつy。計算結果は、xが偽であればx、そうでなければy
x or y xまたはy。計算結果は、xが真であればx、そうでなければy
not x xが偽である

数値は常識的に大小関係が判定されます。文字列、タプル、リストは、長さ(要素の数)が同じですべての要素が両者で一致していれば ==の計算結果はTrueとなり、違うものがあればそこで大小関係が判定されます。文字の大小関係は文字コード表のコードで判定されます。

x in y」でのyはタプルまたはリストで、xy のどれかの要素と同じであれば、計算結果がTrueになります。

次のスクリプトで関係演算子の動作を確認してみます。"A"より"a"のほうが文字のコードが大きいので"abc"のほうが大きくなります。

03-02.py

Python
[RAW]
  1. print( "abc" > "ABC" ) #=> True
  2. x = 10
  3. print( x in (1, 10) ) #=> True
  4. print( x in [1, "a"] ) #=> False

■真偽値

条件式の計算結果が真と判定される、とはどういうことか、もう少し見ておきましょう。Pythonでは、式の計算結果は、必ず真かのいずれかになります。

偽となるのは、計算結果が数値の0と0.0、空の文字列 ""、空のタプル ()、空のリスト []Noneオブジェクト、または Falseオブジェクトのときです。それ以外はすべて真となります。Falseだけが偽ではなく、Trueだけが真というわけでもありません。

03-03.py は、さまざまな値(オブジェクト)が真と判定されるか、偽と判定されるかを表示します。関数tのなかのif文で判定し、真のときは"t"と、偽のときは"false"と表示します。[""]は、""という要素を持つので、真です。

03-03.py それぞれの値が真か偽かを表示する

Python
[RAW]
  1. # -*- coding:utf-8 -*-
  2. def t(v):
  3. if v: print( v, " => t" )
  4. else: print( v, " => false" )
  5. # 数値
  6. t(1) #=> t
  7. t(0) #=> false
  8. t(1.1) #=> t
  9. t(0.0) #=> false
  10. # 文字列
  11. t("a") #=> t
  12. t("") #=> false
  13. # タプル
  14. t((0,)) #=> t
  15. t(()) #=> false
  16. # リスト
  17. t([""]) #=> t
  18. t([]) #=> false
  19. # その他
  20. t(None) #=> false
  21. t(True) #=> t
  22. t(False) #=> false

そうすると、計算結果が0以外かどうかを調べるときは、わざわざ「!= 0」を書かなくても差し支えないことが分かります。0以外かどうかを調べることはよくあり、!= 0 を省略して書く人も多いです。

■if文ふたたび

先ほど else: を使いましたが、if文は、すでに見た単純な形の後ろにelif節やelse節を加えることで、条件式Aが成り立っているときは文Xを実行する、そうでなくて条件式Bが成り立っているときは文Yを実行する、それとも違うときは文Zを実行する、と書くことができます。

文法は、次のようになります。

if 条件式A:
    文
    文
    文...
[elif 条件式B:  ---+
    文             |elif節
    文             |
    文...]...   ---+
[else:          ---+
    文             |else節
    文             |
    文...]      ---+

if文では、ifに続く文、elif節の文、else節の文のどれか一つだけが実行されます。スクリプトの上から順に条件式が判定され、上記の条件式Aが真のときはifに続く文が、条件式Bが真のときはelifに続く文が実行されます。いずれも違うときはelse節の文が実行されます。

elif節はいくつでも書くことができ、その場合もスクリプトの上から順に条件式が真かどうか判定されていきます。

if文を使ってみましょう。03-04.py は、ウィンドウにボールを表示し、画面の枠にぶつかったら跳ね返るように動かします。(画面1)

03-04.py 跳ね返るボール

Python
[RAW]
  1. # -*- coding:utf-8 -*-
  2. import tkinter
  3. # 跳ねるボール
  4. class BallBounce:
  5. def create_window(self):
  6. window = tkinter.Tk() # (1)
  7. self.canvas = tkinter.Canvas(window, bg = "white", width = self.ww,
  8. height = self.wh)
  9. self.canvas.pack()
  10. x = 150; y = 100
  11. self.ball = self.canvas.create_oval(x - 30, y - 30, x + 30, y + 30,
  12. outline = "red", width = 10) # (2)
  13. self.canvas.after(50, self.on_timer) # (3)
  14. return window
  15. def __init__(self):
  16. self.ww = 300; self.wh = 300
  17. # 移動スピード
  18. self.dx = 10; self.dy = 5
  19. self.window = self.create_window()
  20. def run(self):
  21. self.window.mainloop()
  22. # タイマーで呼び出される
  23. def on_timer(self):
  24. x1, y1, x2, y2 = self.canvas.coords(self.ball) # (4)
  25. x1 += self.dx; x2 += self.dx; y1 += self.dy; y2 += self.dy # (5)
  26. # 衝突?
  27. if x1 <= 0 or x2 >= self.ww: # (6)
  28. self.dx *= -1
  29. if y1 <= 0 or y2 >= self.wh:
  30. self.dy *= -1
  31. self.canvas.coords(self.ball, x1, y1, x2, y2) # (7)
  32. self.canvas.after(50, self.on_timer) # (8)
  33. BallBounce().run()

実行結果

順に何をしているか見ていきます;

  1. tkinter.Tk() でウィンドウを生成し、tkinter.Canvas() でボールを描くためのキャンバスを生成します。
  2. ボールは、単純に、Canvas#create_oval() で円を描きます。
  3. ボールを動かすために、定期的・自動的に on_timer メソッドを呼び出してもらいます。after メソッドは、最初の引数の時間を経過したときに自動的に呼び出すメソッド・関数を登録します。時間はミリ秒単位で指定します(ここでは50ミリ秒 = 0.05秒を指定)。
  4. Canvas#coords() は、オブジェクトのキャンバス上での座標を調べたり設定したりします。引数としてオブジェクトを渡すと、現在の座標を調べて返します。戻り値は順に、左上のX座標、Y座標、右下のX座標、Y座標です。
  5. X軸方向に self.dx だけ、Y軸方向にself.dy だけボールを動かします。x1 += self.dx は、x1 = x1 + self.dx と同じ意味で、変数x1の値にself.dx を足した結果を, x1 が指すようになります。

    += だけでなく, -=, *= などもあります。

  6. 左端の座標が0かマイナスの場合、あるいは右端の座標がウィンドウの大きさと同じか大きい場合には、ボールの進行方向を逆にします。Y方向も同じです。if文で条件に合致するかどうか判定します。大小関係を比較する演算子とor を組み合わせています。
  7. 新しい座標が計算できたので、Canvas#coords() に新しい座標を引数として与えます。これでボールが移動します。
  8. 最後に、再びafterメソッドで on_timer を登録しなおします。afterメソッドは, 時間が経過したときに一度だけしか登録した関数を呼び出しません。このサンプルプログラムでは連続して呼び出してほしいので、毎回 on_timer を登録しなおします。

■while文 "〜の間"

while文は、条件式の計算結果が真である間、続く文の実行を繰り返します。実行する文を字下げして書くのは、if文のときと同じです。

文法は、次のようになります。

while 条件式:
    文...

次のスクリプトは、入力された数字をどんどん足していくものです。入力が空のとき(ユーザが何も入力せずにEnterキーを打ったとき)に終了します。while文で、入力結果が空の文字列 "" かどうか調べ、そうでないときに続く3行を実行します。

03-05.py

Python
[RAW]
  1. x = 0
  2. v = input(">>> ")
  3. while v != "":
  4. x += int(v) # whileの外側の変数
  5. print( x )
  6. v = input(">>> ")

実行結果は、次のようになります;

>>> 1
1
>>> 10
11
>>> 25
36
>>>       <= ここでEnterのみ打ったので、終了
$

■for文 "〜のそれぞれについて"

for文は、一定の回数、文の実行を繰り返します。文法は次のとおりです。

for 変数名 in 式リスト:
    文...

式リストは、タプル、リストなど要素を持つ(格納する)ものです。for文は、式リストの要素を前から順番に変数に代入し、続く文を繰り返し実行します。

for文でも、新しいスコープは導入されません。

例えば次のように書きます。

03-06.py

Python
[RAW]
  1. v = 0
  2. for i in (1, 3, 5):
  3. v += i
  4. print( v )

要素の値を累積して表示します。変数 i にタプルの要素1、3、5が順番に代入されて、続く文(print文)が実行されます。実行結果はこうなります;

$ python3 03-06.py    
1
4
9

ところで、プログラムを書いていると、何回目の実行かはどうでもよくて、繰り返す回数だけが重要な場合がよくあります。このようなときは、式リストに range関数を書きます。range関数は、繰り返しを生成します。

range(n)
0 から始まり (n-1) までからなる繰り返しを生成します。
range(start, n)
start から始まり (n-1) までからなる繰り返しを生成します。

for文では、例えば次のように書きます。

03-07.py

Python
[RAW]
  1. y = 0
  2. for x in range(4):
  3. y += x
  4. print( y ) #=> 6 = 0 + 1 + 2 + 3

■break文 "中断"

while文、for文で繰り返しの文を実行しているときに、最後まで繰り返すのを止めて、その場で繰り返しから抜け出すようにしたいことがあります。このような場合には、break文を使います。

break文は、繰り返しの文の中から、その場で脱出します。次の例は、i が3のときに繰り返しを終了します。そのため、1と2しか表示されません。

03-08.py

Python
[RAW]
  1. for i in (1, 2, 3, 4):
  2. if i == 3:
  3. break
  4. print( i )
  5. print("finish: ", i)
実行結果
$ python3 03-08.py
1  
2
finish:  3

■continue文 "次へ進む"

繰り返しのブロックの途中でいったん中断し、whileの条件式の判定に戻ったり、forで次の要素による繰り返しに進むには、continue文を使います。

こちらも、break文と同様、continue と書くだけです。

次の例は、i が2のときに繰り返しのブロックの残りをスキップして、for の式リストの次の要素による繰り返しに進みます。

03-09.py

Python
[RAW]
  1. for i in (1, 2, 3, 4):
  2. if i == 2:
  3. continue
  4. print( i )
実行結果
1
3
4