6. 3大構造 一. 順次

この章から プログラムの3大構造 を紹介します。

  • 順次(本章)

  • 分岐(7 章

  • 反復(8 章

順次 (じゅんじ)とは、処理を順番に実行する ことです。

この章からは対話モードを離れ、処理を ファイルに書いて いきます。 対話モードで学んだことは、ファイルでも同じように使えます。

6.1. はじめてのファイルを使ったプログラム

6.1.1. ファイルを使う準備

まずは、対話モードに quit() と入力して終了します。

「プログラミングするための環境」として準備したエディター、Atomを使います。 Atomで py-practice ディレクトリをプロジェクトフォルダーとして開いてください。 # noqa

次に、Atomを操作して、basic ディレクトリを作ってください。 この名前は、プログラミングの基本(basic)を学ぶためのディレクトリという意味です。

../_images/5-6-2_create_basic_directory.png

basic ディレクトリを作った後のAtom

ディレクトリをまず作り、その中にファイルを作るのがおすすめです。 作業ごとにディレクトリを作る と、PCの中を整理整頓して使っていけます。 本章から 10 章プログラマーの考え方を知ろう」までのプログラムは、 basic ディレクトリに作ります。

最後に、コマンドラインで cd コマンドを使って basic ディレクトリに移動しましょう (カレントディレクトリが py-practice になっていましたね)。

> cd basic

6.1.2. ファイルに処理を書く

ファイルのプログラムを作るときは、Atomを以下の手順で操作します。

  1. ファイルがない場合は、ファイルを作成する

  2. ファイルに文を入力する

  3. ファイルを保存する

まず、 basic ディレクトリの中に hajimete.py というファイルを作ります。

次に hajimete.py に、以下の3行を入力しましょう。 2つの変数 ab を使って、整数の積を計算します(2 章値を変数で扱おう」でも書きましたね)。

hajimete.py
1a = 4
2b = 6
3print(a * b)

入力したら、ファイルを保存してください。 Atomでファイルを保存することで、入力内容がPCの中のファイルに書き込まれます。

6.1.3. プログラムのファイルを実行

それでは、hajimete.py というファイルのプログラムを プログラミング言語処理系で処理 します。 これは、「ファイルのプログラムを実行」「ファイルを実行」とも言われます。

コマンドはOSによって異なります。 以下のうち、該当する方を入力してください。

6.1.3.1. Windowsの場合

PowerShellで python コマンドに続けて、実行するファイルの相対パスを指定 します。

> python hajimete.py

この後にやることは、続く「macOSの場合」でファイルの相対パスを入力した後の部分で説明します。

6.1.3.2. macOSの場合

ターミナル.appで python3 コマンドに続けて、実行するファイルの相対パスを指定 します。

% python3 hajimete.py

ここから先は 「Windowsの場合」のコマンドだけ を示します。 macOSを使っている方 は、python と見かけたら、python3読み替え てください。

ファイルの相対パスを入力した後は、Enter キーを押してください。

> python hajimete.py
24
>

コマンドラインに 24 が表示され、そしてプロンプトが再度表示されています。 ファイルの実行が終わると、プロンプトが再度現れます。

hajimete.py に書かれた処理が 1行目から順に 実行された結果、24 が表示されました。

../_images/5-11_in_order.drawio.png

ファイルのプログラムは1行目から順に処理される

処理系が ファイルを 1行目にある文から 順番に1文ずつ実行する というのが順次です。 後に続く行がなくなったら、ファイルの実行は終わります。 順次により、hajimete.py では \(4 \times 6\) が計算されて、24 と表示されました。

ファイルのプログラムを読むときは、1行目から順番に、何をしている文か理解 しましょう。 処理系の動きをプログラマーの頭の中で再現するのです。

対話モードでは先に入力した処理から順番に実行されましたね。 ファイルの実行は、1行目から1文ずつ対話モードで実行するのと同じなのです。

6.1.4. 練習問題

以下のように処理を足した hajimete.py を実行すると、コマンドラインには何が表示されるでしょうか。

hajimete.py
1a = 4
2b = 6
3print(a * b)
4banzai = "万歳!"
5print(banzai * 3)

「こう思う」と結論が出たら、実際に実行して確かめましょう。

[解答]

表示されるのは2行です。

> python hajimete.py
24
万歳!万歳!万歳!
>

まず 24 と表示されます(3行目の print 関数によります)。 続いて、万歳!万歳!万歳! と表示されます(5行目の print 関数)。

この結果を「当たり前」と感じたら、順次を体得しています! プログラムは1行目から1文ずつ実行されるので、行として上にある print(a * b) が実行されて、24 が先に表示されます。 追加した4,5行目の文から実行されるということはありません。

../_images/5-12_in_order2.drawio.png

1行目から順に実行される

もし、ここで示した結果が表示されない場合は、Atomでファイルを保存したか確認してください。

[コラム] ファイルで体験する print 関数の効能

hajimete.py の3行目で print 関数を呼び出さなかったらどうなるでしょうか。

hajimete.py
1a = 4
2b = 6
3a * b

ファイルを実行しても、a * b の評価結果はコマンドラインに表示されません。

> python hajimete.py
>

a * b を評価していないのではありません。 print 関数を呼び出していないので、コマンドラインに表示されないのです。

表示には print 関数を呼び出す必要がある というのが、対話モードとファイルとの違いです。

[コラム] 新しく知った文法は対話モードでまず試そう

この章から先は、プログラムをファイルに書くことが中心になります。 ですが、対話モードを全く使わなくなるわけではありません。 新しく知った文法は 対話モードでまず試し、使い方を掴んでからファイルに書く のがおすすめです。

私の経験では、新しく知った文法を使ったプログラムをいきなりファイルに書いたとき、実行時にたいてい処理系はエラーを出します。 これは新しく知った文法の使い方を間違えていることが原因でした。 そこで、 ファイルに書く前に対話モードで試し、処理系がエラーを出さない使い方を把握する ようにしています。 対話モードで確認した通りにプログラムをファイルに書けばいいのです。

[コラム] プログラムとコード

この章でファイルのプログラムを扱い始めました。 プログラマーの世界には、プログラムと似た意味の言葉に「コード」があります。

コードという言葉は、プログラムの一部の式や文、それらのまとまりを指します。 プログラムがまとまった処理をし、コードがそのプログラムの部品です。

hajimete.py はプログラムですが、各行をコードと呼んだり、 3行全体を \(4 \times 6\) を計算する部品と見てコードと呼んだりします。

6.2. ファイルに書いた関数

関数を書いたファイルの実行も、順次で説明されます。 ですが、関数の呼び出しは、ファイルを 遡っているように見え ます。 本節で、関数を書いたファイルについて、処理系の動きを頭の中で再現できるようになりましょう。

6.2.1. ファイルで挨拶を表示する関数を作る

関数を使ったファイル aisatsu.py を書いていきましょう。

5 章関数を作って処理をまとめよう」で作った、引数に指定した人への挨拶を表示する関数を aisatsu という名前で定義します。

指定した人への挨拶を表示する関数

箱の名前

aisatsu

箱は何をするか

「〇〇さん、ごきげんよう」と挨拶を表示する

箱に入れるもの

文字列(「〇〇」の部分に入る人の名前)

箱から出てくるもの

なし

aisatsu.py
1def aisatsu(namae):
2    print(f"{namae}さん、ごきげんよう")

対話モードと同様、ファイルでも インデントが必要 です。

このファイルを実行しましょう(実行方法は前節を参照してください)。 どうなると思いますか?

> python aisatsu.py
>

おや、「ごきげんよう」という挨拶は表示されませんでした。 処理系がエラーを出したわけではないですね。 では、なぜ表示されなかったのでしょうか。

プログラミングで何かがうまくいかない状況に陥ったら、過去にうまくいった状態と今のうまくいかない状態を比較 します。 対話モードでは挨拶が表示されていましたね。 5 章関数を作って処理をまとめよう」を思い出してみて、何か気づくことはありませんか?

6.2.2. ファイルでも関数の呼び出しが必要

対話モードでは aisatsu 関数を定義したあと、aisatsu("susumuis")呼び出し ていました。 それに対して、aisatsu.py では、まだ呼び出していません。 ファイルに関数の呼び出しを追加したら、挨拶が表示されそうですね。 この仮説を試してみましょう(変更点は5行目だけです)。

aisatsu.py
1def aisatsu(namae):
2    print(f"{namae}さん、ごきげんよう")
3
4
5aisatsu("susumuis")  # ((aisatsu関数を呼び出す))

コマンドラインで実行すると、挨拶が表示されます!(仮説は正しく、問題は解消しました!)

> python aisatsu.py
susumuisさん、ごきげんよう
>

6.2.3. 関数を含むファイルの読み方

処理系が aisatsu.py をどのように処理するか、見ていきましょう。 順次により、ファイルは 1文目から順番に実行され ます。

  1. 処理系は1,2行目の aisatsu 関数定義の文を実行します。これで aisatsu 関数が 使えるようになり ます

  • この処理では、関数は呼び出されません。使えるようになるだけです

  1. 処理系は5行目の文、 aisatsu 関数の 呼び出し を実行します

  • 関数呼び出しにより、関数にまとめられた文が1文ずつ順に実行されます(まとめられた文を順次実行します)

  • このファイルでは2行目の文が実行されます(namae には引数 "susumuis" が代入されます)

../_images/5-16_in_order_function.drawio.png

関数を呼び出すと、関数に定義した文が順に実行される

関数を2回呼び出すように aisatsu.py を変えてみましょう。

aisatsu.py
1def aisatsu(namae):
2    print(f"{namae}さん、ごきげんよう")
3
4
5aisatsu("susumuis")
6aisatsu("nao_y")

処理系は次の順でプログラムを実行します。

  1. 1,2行目の aisatsu 関数の定義を実行します

  2. 5行目の aisatsu 関数の呼び出しを実行します

  • namae"susumuis" が代入された状態で2行目が実行されます

  • 関数の呼び出しの実行が終わると、続く文の実行に進みます

  1. 6行目の aisatsu 関数の呼び出しを実行します

  • namae"nao_y" が代入された状態で2行目が実行されます

  • 関数の呼び出しの実行が終わると、続く文の実行に進みます(続く文がないのでプログラムの実行終了です)

このことから、関数を書いたファイルを処理系がどう実行するかを知りたいときは、 「関数呼び出しを見つけたら、関数の定義を探す」という読み方になります。 # noqa

[コラム] 関数を定義より先に呼び出すとエラー

関数を定義する前に関数を呼び出したらどうなるでしょうか。

aisatsu.py(処理系がエラーを出します)
1aisatsu("susumuis")
2
3
4def aisatsu(namae):
5    print(f"{namae}さん、ごきげんよう")

定義されていない関数の呼び出しで、処理系は NameError を出します。

> python aisatsu.py
Traceback (most recent call last):
  File "aisatsu.py", line 1, in <module>
    aisatsu("susumuis")
NameError: name 'aisatsu' is not defined
>

定義が1行目より後にありますね。 1行目の文を処理するときには aisatsu 関数が使えるようになっていないのです。

処理系が NameError を出さなくするために、ファイルでは、関数の 定義を先に、呼び出しを後に 書きましょう。

6.2.4. 練習問題

以下の「挨拶文を返す関数」が返す挨拶文をコマンドラインに表示するように、aisatsu.py を変更してみましょう。 5 章関数を作って処理をまとめよう」で作った関数から、返り値を少し変えています。

挨拶文を返す関数

箱の名前

aisatsu_bun

箱は何をするか

「〇〇さん、ごきげんよう^o^」という挨拶文を返す

箱に入れるもの

文字列(「〇〇」の部分に入る人の名前)

箱から出てくるもの

文字列(挨拶文)

[解答]

aisatsu.py
1def aisatsu_bun(namae):
2    return f"{namae}さん、ごきげんよう^o^"  # ((値を返す))
3
4
5# ((aisatsu_bun("susumuis")の返す値をprint関数で画面に表示する))
6print(aisatsu_bun("susumuis"))

実行すると、顔文字付きの挨拶が表示されます。

> python aisatsu.py
susumuisさん、ごきげんよう^o^
>

6行目の文(式) print(aisatsu_bun("susumuis")) は、内側から 評価されます。 aisatsu_bun("susumuis") が評価され、返り値が print 関数の引数となります。

ある関数の呼び出しを別の関数の引数にするというこの書き方は、プログラムの行数が減るのでたびたび使われます。 ただし、関数3つ以上でやると読みやすさを損ねてしまいます。 3つ以上のときは、途中結果を変数に代入する方が読みやすいでしょう。

[コラム] 関数定義の下が2行空いているのはなぜ?

aisatsu.py で、aisatsu 関数の定義の下に2行、空の行(空行:くうぎょう)を入れました。 これはPythonのプログラムを 読みやすく書くための慣習に従っている ためです。 1 章プログラムで数と文字を扱ってみよう」のコラムで取り上げた 演算子の前後の半角スペースと同じで、プログラマーのためのものです。

空の行の数は処理系には影響しません。 空の行が3行以上あっても、1行でも、なくても、aisatsu.py を実行すれば同じ結果になります(気になる方は試してみてください)。

本書では、Pythonのプログラムを読みやすく書くための慣習に従い、本章以降も関数定義の下に2行空行を入れます。

[コラム] エディターだとプログラムが書きやすい

この章ではエディターを使ってプログラムを書きました。 「対話モードに慣れてきたのに、なぜわざわざエディターを使うのだろう」と疑問に思うかもしれませんね。 理由は、対話モードで書くよりも プログラムを書きやすい からです。

例えば関数を作る時、対話モードで改行すると、前の行には戻れません。 それに対して、エディターでは 入力カーソルを好きな位置に移動 できます(前の行の内容も簡単に直せますね)。

さらにエディターはプログラムを書きやすくする機能をもっと持っています。 エディターは、ファイルの拡張子からプログラミング言語を判断します。

拡張子が py のファイルについては、必要なところは 自動でインデント が入ります。 例えば、関数を定義するとき、def の行をコロンまで入力して改行すると、 次の行は半角スペース4つ分インデントした位置から始まります。 タイプする数が減って、プログラムが書きやすいですね。

../_images/5-15_atom_auto_indent.png

インデントした位置から入力できる

他にも、変数や関数呼び出しのタイプ中に 候補を提示 したり、変数を別の名前に 一括置換 できたりします。 Atomを使って快適にプログラミングしたければ、 自分で調べたり、長くAtomを使っている先輩プログラマーにコミュニティで質問したりしてみてはいかがでしょうか。

[コラム] エディターだとプログラムが読みやすい

エディターはプログラムを書きやすくするだけではなく、読みやすくする機能も提供します。 例えば、Atomでは、値が型ごとに色分け されます。

../_images/5-17_atom_highlight.png

Atomでは、数値はオレンジ、文字列は黄緑、関数は水色で示される

また、プログラミング言語における キーワード (Pythonでは defreturn など) も色で区別 されます。

対話モードでは文字の色は全部同じでしたね。 それと比べると、色分けされたプログラムは読みやすく感じるのではないでしょうか。

6.3. 順次の練習:挨拶するプログラム

前の節で作った aisatsu.py を実行すると、常にsusumuisに挨拶しますね。

> python aisatsu.py
susumuisさん、ごきげんよう^o^
>

これは挨拶の相手がsusumuisとプログラム中に書かれているからです。 練習として、挨拶をする相手の名前を プログラム実行中に指定 できるように変更しましょう。

6.3.1. 練習問題:挨拶する相手を入力する

4 章プログラムの入力と出力を扱おう」で紹介した、 入力を受け取る関数 input を使いましょう。

入力した名前を aisatsu_bun 関数に渡せば、その人への挨拶が返りますね。

[解答] 正解例

aisatsu.py
1def aisatsu_bun(namae):
2    return f"{namae}さん、ごきげんよう^o^"
3
4
5namae = input("名前を入力してください:")
6print(aisatsu_bun(namae))  # ((変数 namae を渡すように変更))

5行目で input 関数を使って、入力された名前を namae に代入します。 6行目で aisatsu_bun 関数を呼び出して、入力された名前向けの挨拶を表示します。

動作確認しましょう。 好きな名前を入力してください。

> python aisatsu.py
名前を入力してください:nikkie
nikkieさん、ごきげんよう^o^
>

入力した名前に対して挨拶するようになりました! これで プログラムを変更しなくても 、susumuisにもnao_yにも挨拶できます。

:本書のプログラムと手元のプログラムが違っても、同じように動いていれば正解です。 例えば、5行目の input 関数をファイルの先頭(1行目)に移しても、動きは変わりません。

プログラミングで使う値はプログラムに 全て書いておかなければならないわけではありません 。 プログラムの実行中に入力し、その値を変数に代入して、プログラムで使えます。

[コラム] 飛ばして先に進む読み方もOK!

順次を学んだ後、残りの3大構造を飛ばして、実際に使えるプログラムを作る他書をのぞいてみることもできます。 他書では、3大構造を全て知っていることを前提にして解説が進むでしょう。 初めて知ることがあれば一時戻って、理解に必要な部分をつまみ読みしてください。

皆さんの中には基礎から着実に押さえたい方もいれば、実践の中で学びたいという方もいるでしょう。 基礎から着実に押さえたいという方は、引き続きお付き合いください。 「そろそろ実践したくなってきた」という方は、実際に使えるプログラムを作る章に挑戦してみてはいかがでしょうか (本は前から順番に読まなければならないものではない ですからね)。