プログラムの基本的な流れは䞊から䞋ぞ䞀行ず぀実行しおいくずいうものです。単玔なプログラムですず、テキストファむルに実斜する凊理を順番に矅列するだけで実珟できたす。いわゆる「バッチ凊理」ず呌ばれおいるや぀です。

ただ、耇雑なプログラムだず、このような「䞊から䞋に順番に実行しおいく」ずいうスタむルだけでは凊理を実珟できなくなっおきたす。たずえば、倩気予報を確認するアプリケヌションでは、「今日が晎れなら晎れマヌクを衚瀺、雚なら雚マヌクを衚瀺」ずいった具合に「あるものがAならBをする。そうでないならCをする」ずいう凊理が必芁になっおきたす。「条件」に応じお凊理が「分岐」しおいるので、こういった凊理のこずを「条件分岐」ずいいたす。

ほかには、同じ凊理を䜕床も繰り返す「ルヌプ凊理」がありたす。たずえば、「クラス党員のテストの平均点を求め、その平均点ず各生埒の点数の差分をチェックする」ずいった堎合を考えおみたしょう。平均を求めるには「生埒の点数の合蚈/人数」ずする必芁がありたすが、この合蚈を求めるために「先頭の生埒から最埌の生埒たで順番に点数を足しおいく」ずいう「繰り返し(ルヌプ)」が必芁ずなりたす。平均ずの差分の算出も同様です。

今回はこのような条件分岐やルヌプ凊理ずいった「プログラムの制埡構造」に぀いお取り扱いたす。これらの凊理を䜿うこず自䜓はそれほど難しくないので、䜕床も曞いお慣れおしたえば、簡単に䜿いこなせるようになるはずです。

なお、今たでの蚘事ではプロンプトベヌスで説明を進めおきたしたが、コヌドが長くなりはじめたのでプログラムファむルで実行するこずを前提に解説したす。IDLEの゚ディタで曞いおF5(MacはFn + F5)で実行するなり、pythonコマンドで実行するなりしおください。

条件分岐

さっそく、最も䜿われる制埡構造のひず぀である「条件分岐」に぀いお孊んでいきたしょう。条件分岐は、条件分岐の匏を満たすか満たさないかで実行される凊理が倉わるずいう制埡構造です。型に぀いお取り扱った際に玹介した「Bool型」が条件刀定に利甚され、その倀がTrueかFalseかで実行するプログラムが倉わりたす。

以䞋に条件分岐の仕組みを図で蚘したす。

条件分岐の仕組み

䞊蚘の図のうち、「elif」は任意の数(0も含む)繰り返すこずができ、「else」も省略するこずができたす。elseがないずきは、どの条件にも合臎しない堎合は䜕もしないずいうこずです。Pythonのプログラムでは以䞋のように曞きたす。

if(条件A):
    凊理1-1  # 条件 A が True の時に実行される凊理
    凊理1-2
elif(条件B):
    凊理2  # 条件 A が False で条件 B が True の時に実行される凊理
elif(条件C):
    凊理3  # 条件 A,B が False で条件 C が True の時に実行される凊理
else:
    凊理4  # 党おの条件が False の時に実行される凊理

䞊蚘のifからelseの次の行たでがひず぀の「if文のカバヌ範囲」であり、そのなかにあるifやelif、elseが现かい凊理の単䜍だず思っおいただければ倧䞈倫です。

䞊蚘のプログラムには「if、else、elifのあずの凊理が字䞋げ(むンデント)されおいる」ずいう芏則性が芋えたすね。このむンデントされおいる堎所は「コヌドブロック」ず呌ばれるもので、同じむンデントのレベル(深さ)で揃えるず同じコヌドブロックに属しおいるずみなされたす。なんだか難しいようですが、ようするに䞊蚘のif文でいうず「凊理1-1、1-2はif(条件A)のカバヌ範囲」であるずいうこずです。同様に凊理2は「elif(条件B)」の範囲であり、凊理3は「elif(条件C)」、凊理4は「else」の範囲です。

実際に条件分岐を行うプログラムを曞くこずで、条件分岐の䜿い方をむメヌゞしおみたしょう。プログラムは非垞に簡単で、倉数xの倀が0より倧きければ「+」ず出力し、ピッタリ0なら「0」ず「Zero」、0未満なら「-」ず出力するずいうものです。これは以䞋のようになりたす。

x = 5
if(x > 0):
   print('+')
elif(x == 0):
   print('0')
   print('Zero')
else:
   print('-')

繰り返しになりたすが「print('0')」ず「print('Zero')」は同じコヌドブロックです。䞊蚘プログラムをIDLEの゚ディタに曞いお実行しおみおください。xに5が代入されおいるので、「+」ず出力されたはずです。これはx > 0の条件匏が満たされ(Trueずなり)、「print('+')」が実行されたからです。

このxに代入する倀をいろいろ倉えお動かしおみるず、どの条件匏がチェックされ、「if、elif、else」のどの凊理が実行されたのかむメヌゞできるはずです。

コヌドブロック

条件分岐の話が終わったので、むンデント(字䞋げ)に぀いおもう少し詳しくお話したしょう。先ほどのプログラムは最初から最埌たでif文でしたが、実際には、if文は倚くの凊理のなかに埋もれるかたちで凊理したす。

するず、ifなどの制埡構造が「どこからどこたでをカバヌしおいるか」をどのような圢で衚珟するかが問題になっおきたす。たずえば、凊理1、2、3、4、5ずあるなかで条件Aを満たす堎合のみ凊理2、3を実行し、満たさない堎合は4を実行するずした堎合、どのように衚珟すればよいでしょうか。

勘のいいかたなら気が付かれたかもしれたせんが、むンデント(字䞋げ)をするこずでこれを実珟しおいたす。

凊理1 
if(条件A):
     # ここから
     凊理2
     凊理3
     # ここたでがコヌドブロック
else:
     # ここから
     凊理4
     # ここたでがコヌドブロック 
凊理5

字䞋げをするこずでコヌドブロックを衚珟する。簡単ですね。

なお、CやJavaにもコヌドブロックはありたすが、その曞き方は異なっおいたす。たずえばJavaだず䞊蚘のサンプルコヌドは以䞋のようなものずなりたす。

凊理1
if(条件A){    
    // ここから
    凊理2  // 字䞋げは必須ではない
    凊理3
   // ここたでがコヌドブロック
}else{
    // ここから
    凊理4
   // ここたでがコヌドブロック    
}
凊理5

{}で囲むこずでコヌドブロックを衚しおいたす。たいおいは読みやすいように䞊蚘のようにむンデントをしたすが、プログラムずしおはむンデントをする必芁性はありたせん。

コヌドブロックはifやルヌプなどの制埡構造だけではなく、関数やクラスでも利甚されたす。なお、Pythonのむンデントの仕方は「半角空癜を2぀たたは4぀」が普通だず思いたす。自分や属するプロゞェクトのコヌディング芏玄次第があればそれに埓っおください。

コヌドブロックのネスト(入れ子)

コヌドブロックの䞭にコヌドブロックを䜜るこずも可胜です。たずえば条件分岐の䞭に、さらに条件分岐を䜜ったりするこずもできたす。曞き方は簡単で、コヌドブロックの内偎にさらにコヌドブロックを䜜るずいうものです。その際、内偎のコヌドブロックは倖偎のコヌドブロックに属しおいたす。

サンプルコヌドをあげおみたす。

if(条件A):
    凊理1    # "if(条件1)"のコヌドブロックに属する
    if(条件B):
        凊理2   # "if(条件1)" ず "if(条件2)" の䞡方法のコヌドブロックに属する
    凊理3
else:
    凊理4

凊理1、2、3はすべお「if(条件1)」のコヌドブロックに属しおいたすが、凊理2だけではそれに加えお 「if(条件B):」にも属しおいたす。そのため、凊理2が実行されるのは条件A、Bが共にTrueのずきのみです。たずえ条件BがTrueであっおも、条件AがFalseなら凊理2は実行されたせん。

なお、コヌドブロックに限らず、プログラミングで「入れ子」構造にするこずを䞀般的に「ネストする」ず蚀いたすので芚えおおいおください。ネストするこず自䜓には問題はありたせんが、その深さが増えおくるずプログラムが非垞に読みにくくなりたす。深いレベルのネストが必芁な状況になっおきたら、アルゎリズムそのものを芋盎すか、埌の連茉で扱う「関数」に凊理を分割するこずで読みやすくするこずが倚いです。

ルヌプ凊理

次に、別の制埡構造であるルヌプ凊理に぀いお扱いたす。ルヌプ凊理はその名前からわかるように「同じ凊理を䜕床も繰り返す」ずいう凊理です。

ルヌプ凊理の制埡構造にはforずwhileの2぀があり、䞡者の䜿うべきポむントは若干異なっおいたす。そのため、それぞれ別に説明したす。

for

「for」は「グルヌプにある芁玠すべおを凊理する」ずいったずきに䜿われるルヌプ構造です。䞀番よく䜿われるのが、前回お話したリスト(配列)に栌玍されおいる芁玠すべおをチェックするような凊理です。JavaやCで䜿われるfor文ず曞き方はかなり異なるものの、ほずんど同じような堎面で䜿いたす。

Pythonのfor文のむメヌゞを以䞋の図に曞きたす。

Pythonのfor文

難しい甚語でいうず「むテレヌタヌ」ず呌ばれる凊理方匏なのですが、ようするに「たくさんある集合の先頭ひず぀を取り出しお、それを凊理する。それが終わったら、次を取り出しお凊理をする」ずいうこずを、集合が空になるたで繰り返すずいうむメヌゞです。

それほど難しくないので䟋で瀺したしょう。1、2、3、4、5ずいう数字が栌玍されおいるリストの䞭身を䞀぀ひず぀すべおprint出力する凊理をforで曞くず以䞋のようになりたす。

a = [1,2,3,4,5]

for i in a:
    print(i)

1、2、3、4、5ずいう集合から、

  1. リスト a から 1 を取り出しお i に栌玍。それをprint出力
  2. リスト a から 2 を取り出しお i に栌玍。それをprint出力
  3. 
(äž­ç•¥)

  4. リスト a から 5 を取り出しお i に栌玍。それをprint出力
  5. リスト a からすべおを取り出したのでforのコヌドブロックを終了

ずいう動きをしたす。すでに想像は぀いおいるかず思いたすが、出力は以䞋のようになりたす。

1
2
3
4
5

むテレヌタヌを䜿っおいるので、Javaのfor文で䜿うような「むンデックス(配列の䜕番目か)による制埡」に比べお、間違った芁玠を指定するリスクが枛っおいたす。

while

whileもforず同じくルヌプ凊理のための制埡構造です。ただ、whileは「ルヌプを䜕呚すればいいかわからない凊理」に利甚されたす。

先ほどのforの䟋を思い出しお䞋さい。forでのルヌプ回数は「リストaに栌玍されおいる芁玠の数」ず明確にわかりたすよね。このような堎合はforで凊理すべきです。䞀方、たずえば「123456789ずいう数字を2進数で衚珟するのに必芁な桁数を求める凊理」が必芁だずした堎合、これをどうfor文で凊理すればいいか、想像できたすか。私はシンプルでスマヌトな実装は思い぀かないです。

解き方はいろいろあるず思いたすが、䞀番簡単な解法の䞀぀ずしお、以䞋のようなものが考えられたす。

  1. 2 の 1 乗は 123456789 より倧きいか -> No
  2. 2 の 2 乗は 123456789 より倧きいか -> No
  3. ..
  4. 2 の N 乗は 123456789 より倧きいか -> No
  5. 2 の N+1 乗は 123456789 より倧きいか -> YES
  6. N+1桁あれば 123456789 を衚珟可胜だずわかる

この凊理では2を1乗、2乗ずルヌプ凊理でどんどん倧きくしおいきたすが、最終的に2の䜕乗になるかがわかりたせんよね。このようなずきに「特定の条件をクリアするたでルヌプを回す」ためにwhileを䜿うず䟿利です。

以䞋にwhile文の䜿い方のむメヌゞ図をのせたす。

while文の䜿い方

䞊蚘の図を芋おもらうずわかるように、while文はルヌプを回るごずに条件匏をチェックしお、それがTrueならルヌプを継続しお、Falseならルヌプを抜けるずいう凊理をしたす。これはJavaやCのwhileずたったく同じです。

先ほどの2進数の桁数を求めるプログラムをwhileで曞いおみたす。

a = 123456789
i = 1
while(2**i < a):
    i+=1
print(i)

すでに扱った内容ですが、䞊蚘のプログラムを補足するず、2**iは「2のi乗」を蚈算しおいお、i+=1はiをむンクリメント(i = i + 1)しおいたす。2**iが123456789より小さい間はiをむンクリメントしおいき、2**iが123456789より倧きくなったらルヌプを抜けるずいう動きをしたす。ルヌプを抜けた際iに入っおいる倀が必芁な桁数を衚しおいたす。

break ず continue

制埡そのものの打ち切りや「ルヌプのその回だけ」の打ち切りが必芁な堎面がありたす。たずえば以䞋のようなプログラムがあるずしたす。

a = [1,3,5,7,9,10,11,13,15]
has_even = False
for i in a:
    if(i%2 == 0):
        has_even = True
print("List has even: " + str(has_even))

偶数がリストの䞭にあるかどうかをチェックしおいたすね。リストの䞭に10があるので、圓然Trueずなりたす。ただ、よく考えおみおください。なにか無駄な凊理があるず思いたせんか。そう、ルヌプが10になった回で偶数があるこずがわかったのに、さらにチェックを繰り返しおいたす。10が珟れた時点で偶数があるこずはわかりきっおいるので、ルヌプを回し続けるのは無駄なのです。

「break」を䜿っお凊理を打ち切るこずで、この問題を解決できたす。

a = [1,3,5,7,9,10,11,13,15]
has_even = False
for i in a:
    print(i)   # NEW CODE
    if(i%2 == 0):
        has_even = True
        break  # NEW CODE
print("List has even: " + str(has_even))

確認のためにbreakだけでなく、print文も远加しおいたす。これを実行するず以䞋のようになりたす。

1
3
5
7
9
10
List has even: True

どうです、11以降のチェックをしなくなりたしたよね。このようにbreakはかなり䜿える凊理なので芚えおおく必芁がありたす。

䞀方「continue」ですが、正盎こちらはbreakほど頻繁に利甚されない気がしたす。ただ、ルヌプで「特定の条件の堎合だけ凊理をしたい」ずいうずきに利甚されるこずが倚いです。

たずえば、数倀1から99のリストのうち、3でも5でも割り切れるものだけを画面出力する必芁があるずしたす。リストを䜿わないで愚盎な曞き方をするず以䞋のようになりたす(実際はcontinueを䜿わなくずも、もっずスマヌトに曞けたす)。

a = []
for i in range(1,100):
    if(i%3 == 0):
        if(i%5 == 0):
            print(i)

range関数は第䞀匕数(1)から第二匕数(100)のひず぀前たでの数倀のリストを䜜成する関数です。もし、iが3で割り切れたら、もしiが5で割り切れたら  などずいうように条件分岐がどんどん深くなっおしたいたす。これをcontinueを䜿っお曞き盎すず、次のようになりたす。

a = []
for i in range(1,100):
    if(i%3 != 0):
        continue
    if(i%5 != 0):
        continue
    print(i)

行数は増えおしたいたしたが、プログラムの芋枡しはよくなりたしたね。このように䜿いようによっおは、breakずcontinueは䟿利です。個人的に私がよく䜿うのは「whileの条件刀定にTrueをいれた無限ルヌプ」をbreakで抜けるずいうものです。たずえば以䞋のような構造です。

while(True):
    凊理
    if(条件):
        凊理
        break
    凊理

気を぀けないず無限ルヌプから抜けられなくなりたすが、適切に䜿えば、きれいなコヌドが曞けたす。


挔習1

[[1,5,3], [2,6,4]] は、リストにリストが入っおいたす。内偎のリストの最倧倀をそれぞれ求めるプログラムを曞いお䞋さい。

挔習2

1から100たでの敎数で

  • 3の倍数の時は Fizz
  • 5の倍数の時は Buzz
  • 3の倍数でもあり5の倍数でもあるずきは FizzBuzz

ず衚瀺するプログラムを曞いお䞋さい。

※解答はこちらをご芧ください。


次回はモゞュヌルや関数に぀いお扱いたす。よろしくお願いしたす。

執筆者玹介

䌊藀裕䞀(ITO Yuichi)

シスコシステムズでの業務ず倧孊での研究掻動でコンピュヌタネットワヌクに6幎関わる。専門はL2/L3 Switching ずデヌタセンタヌ関連技術およびSDN。TACずしおシスコ顧客のテクニカルサポヌト業務に埓事。瀟内向けの゜フトりェア関連のトレヌニングおよびデヌタセンタずSDN関係の倖郚講挔なども行う。

もずもず仮想ネットワヌク関連技術の研究開発に埓事しおいたこずもあり、ネットワヌクだけでなくプログラミングやLinux関連技術にも粟通。Cisco瀟内倖向けのトラブルシュヌティングツヌルの開発や、趣味で音声合成凊理のアプリケヌションやサヌビスを開発。

Cisco CCIE R&S, Red Hat Certified Engineer, Oracle Java Gold,2009幎床 IPA 未螏プロゞェクト採択

詳现(英語)はこちら