第7回 これまでの復習と応用#


Open In Colab


この授業で学ぶこと#

第4回までで、プログラミングにおける材料と道具にあたるデータ型と関数・メソッドについて学び、第5回・第6回で処理の流れを制御する方法について学んだ。実はこれまでに学んだ文法だけで、プログラミングで必要なほとんどの処理を実現することができる。ただし、各文法と実用的な処理の間には隔たりがあり、複数の要素を適切に組み合わせる必要がある。また定番の処理は、世界中の開発者によりライブラリという形にまとめて公開されており、それらを利用することで効率的にプログラムを作成できる。

今回は、これまでに学んだ文法を組み合わせてより高度な処理を実現する方法と、ライブラリから関数等を読み込んで利用する方法について、具体的な例を交えながら学ぶ。

変数を使いこなす#

まずはif文の復習も兼ねて以下の問題に取り組んでみよう。

練習1
2つの数値 ab が与えられるとき、ab のうち大きい方の値を print するコードを作成しなさい。

# a、b の一例
a = 3
b = 2

# 以下にコードを作成し、以下の部分のみ提出する

この応用として、次の問題を考える。

例題
3つの数値 abc が与えられるとき、これらの最大値を print するコードを作成しなさい。

このコードを1つのif文だけで実現することもできる。そのためには abc の6通りの大小関係についてif、elif、elseで条件分岐して、それぞれのケースで最大になる変数を print すれば良い(例えば、a > b and b > c のとき print(a) とする)。ただし、この方法では条件式が複雑になりがちで、比較する数値が4つ、5つと増えるとコード量も膨大になる。

最大値を効率的に求めるのに、以下のような方法がある。

  • まず、最初の値 a を一時的な変数 tmp に入れる[1]

  • 次に、この変数 tmp と2番目の値 b を比較し、b のほうが大きければ tmpb に置き換える。

  • 最後に、tmpと3番目の値 c を比較し、c のほうが大きければ再び入れ替える。

こうすると、最終的に tmp には最大値が残るので、これを出力すればよい。

# a, b, c の一例
a = 1
b = 3
c = 2

tmp = a
if tmp < b:
    tmp = b

if tmp < c:
    tmp = c
print(tmp)

このように1つの問題をより細かい処理に分解し、前の処理の結果を変数に保存しながら次の処理に進む方法は、プログラミングの定石の一つである。

練習2
3つの数値 abc が与えられるとき、これらの最小値を print するコードを作成しなさい。

# a、b、c の一例
a = 2
b = 1
c = 3

# 以下にコードを作成し、以下の部分のみ提出する

練習3
2つの変数 ab が与えられるとき、それぞれの変数の値を交換するコードを作成しなさい。つまり、例えば a = "犬"b = "猫" という変数が与えられた場合、a = "猫"b = "犬" という状態にしなさい。ただし採点の都合上、print してはいけない。
ヒント: 単純に a = b などとすると b に代入する前に a の値が失われてしまうので、もう一つの変数 tmp を用意して a の値を一時的に保存する必要がある。

# a、b の一例
a = "犬"
b = "猫"

# 以下にコードを作成し、以下の部分のみ提出する

文のネスト#

これまでに学んだif文、for文、while文は、それぞれ内側のブロックに入れ子的に使用することもできる。このような入れ子構造のことをネストという。

_images/nest.png

Fig. 13 文のネスト#

入れ子構造を作るには、ブロックの中にさらにヘッダーとブロックを作る。したがって、内側のブロックはTab文字2つ分インデントすることになる。

ブロックの抜け方はこれまでと同様、インデントの大きさをもとに戻せばよい。上の図のようにインデントをTab文字1つ分に戻せば、もとのブロックの処理の続きを書くことができるし、インデントをなくせばブロック外の処理の続きを書くことができる。

以下でいくつか例を見てみよう。

for文とif文の組み合わせ#

例1: break文

for文とif文を組み合わせる簡単な例として、break文を使ったものを紹介する。

まず、0 から 9 までの数字を順に出力するプログラムは次のように書けるのであった。

for i in range(10):
    print(i)

for文のブロックに次のようなif文を追加してみる。

for i in range(10):
    if i == 3:
        break
    print(i)

これを実行すると数字の出力は 2 で止まる。これは i == 3 のときにif文のブロックに入り break が実行されるためである。 break は「繰り返し処理を強制的に終了する」働きをもつ。

例2: リストの最大値

最大値を求める問題を再び取り上げる。要素の数が増えてくると、それぞれに変数を設定するのは非効率なので、リスト data として与えられるとしよう。ここで次の問題を考える。

例題
数値からなるリスト data が与えられるとき、data の要素の最大値を print するコードを作成しなさい。

この例題も、3変数の場合とほとんど同じ考え方で解くことができる。コード例を以下に示す。

data = [1, 3, 5, 2]

tmp = data[0]
for v in data:
    if tmp < v:
        tmp = v
print(tmp)

まず最大値を求めるための変数 tmp を用意し、data[0] で初期化しておく。そしてfor文で data の要素を前から順に見ていき、tmp より大きい要素があれば tmp をその値に更新する。そうすれば最終的に tmp には最大値が残るので、それを出力すれば良い。

練習4
数値からなるリスト data が与えられるとき、data の要素の最小値を print するコードを作成しなさい。

# dataの一例 (この例では 1 と出力するのが正しい)
data = [2, 1, 3]

# 以下にコードを作成し、以下の部分のみ提出する

二重ループ#

for文の中にfor文をネストさせたものを二重ループという。 二重ループを使うと、複数の要素のすべての組み合わせを簡単に処理できる。

例1: 九九を表示する

次のコードは、九九の一部を表示する例である。

for i in range(1, 5):    # iは1から4まで変化
    for j in range(1, 4):  # 各iに対して1から3まで繰り返し
        print(f"{i} * {j}{i * j} です。")

range 関数に引数を2つ渡しているが、range(a, b) により生成されるイテラブルオブジェクトは、a から b-1 までの整数を順に生成する。この例では、

  • 外側のループで i は1、2、3、4と順番に変化し、それぞれに対して

  • 内側のループで j が順に1、2、3と変化する。

よって、合計で12回 print 関数が実行されることになる。実行結果を見て ij がどのように増えていくか確認しよう。

例2: 二次元リスト

二重ループは、二次元リストを処理する際にもよく用いられる。二次元リストとは、要素がリストになっているリストのことである。例えば以下は二次元リストである。

data = [[1, 2], [3, 4]]

これに対し、リスト以外(整数や文字列など)を要素とするリストを一次元リストと呼ぶ。上の例で言えば、[1, 2][3, 4] は一次元リストであり、これらを含む data は二次元リストということになる。

二次元リストの要素にアクセスするには、インデックスを2つ使う必要がある。例えば、上記のデータから値 3 を取り出したい場合は、data[1][0] と書く。

data[1][0]

このような二次元リストのすべての要素を処理するには、二重ループを使うのが便利である。具体例として、すべての要素を表示するプログラムを見てみよう。

data = [[1, 2], [3, 4]]

for row in data:  # 外側のループで各一次元リストを取り出す
    for v in row:   # 内側のループで一次元リスト内の値を順番に取り出す
        print(v)
  • 外側のループで、data の各要素(ここでは [1, 2][3, 4])が順番に row に代入される。

  • 内側のループでは、この row の中身が順番に変数 v に代入され、それが表示される。

また、この処理は以下のように range とインデックスを利用して書くことも可能である。

data = [[1, 2], [3, 4]]

for i in range(len(data)):
    for j in range(len(data[i])):
        print(data[i][j])

どちらの方法もよく用いられるので、慣れておくと良い。

練習5
数値からなる二次元リスト data が与えられるとき、一番内側の要素の合計値を求めて print するコードを作成しなさい。

# dataの一例 (この例では10と出力するのが正しい)
data = [[1, 2], [3, 4]]

# 以下にコードを作成し、以下の部分のみ提出する

total = 0  # 合計値を保存する変数
# ここに二重ループを書く

print(total)

モジュールとimport#

これまでに使ってきた関数やデータ型は「組み込み関数」や「組み込み型」と呼ばれ、Pythonがあらかじめ用意しているものである。これに対して、自分で作成した関数や、誰かが作って公開した関数を利用するには、それをPythonに取り込む必要がある。この操作がimport文である。

Pythonでは、関連した関数やデータ型をひとまとめにしたファイル(モジュール)を、必要に応じて読み込んで使うことができる。モジュールの拡張子は .py である。モジュールには、

  • 他の人が作った便利な関数を簡単に使える

  • 同じコードを繰り返し書く必要がなくなり、効率的にプログラムが書ける

  • プログラムの構造が見やすくなる

などの利点がある。

例えば、乱数を生成する random モジュールを使う場合は次のように書く。random モジュールの中の choice 関数は、インポート後に random.choice() とすることで使用することができる。 これはリストを引数として受け取り、その要素をランダムに1つ返す関数である。

import random

cand = ["りんご", "キウイ", "バナナ"]
random.choice(cand)

また特定の関数だけをモジュールから読み込む方法もある。

from random import choice

cand = ["りんご", "キウイ", "バナナ"]
choice(cand)

この場合、関数名の前にモジュール名を付けずに使える。

さらに短い名前でモジュールを呼びたい場合は、次のように別名を指定してインポートできる。

import random as r

cand = ["りんご", "キウイ", "バナナ"]
r.choice(cand)

ライブラリのインストール

Pythonのライブラリは、標準ライブラリ(インストール不要で最初からPythonに含まれている)と外部ライブラリ(自分で追加インストールが必要)に分かれている。 外部ライブラリをインストールするには pip コマンドを使う。例えば、pandas というライブラリをインストールしたい場合、pip install pandas のように書く。 こうして追加したライブラリも、上記のようにimportして使える。