関数とは

meg01

今回はPythonの「関数」について学んでみましょう!

関数?数学の y = 2x + 5 みたいな?

mana06

数学かあ…

gaku03
meg08

いやいや,数学の関数とはまた違うものですよ!

そうなんですね。

mana12
meg01

複雑なプログラムになってくると,同じ処理が何度も出てきたり,どんどんプログラムが長くなってしまいます。

meg04

そういうときに関数が便利です。

関数は,何度も使うプログラムをひとまとめにして呼び出せる便利な機能です。

よくわからないなあ…

gaku04
meg01

具体的にみたほうがわかりやすいので,例をみながらやっていきましょう!

○時間○分○秒というのを○秒に変換してくれる関数を作ってみましょう。

○時間○分○秒を○秒に変換する関数

  • def get_time(hour, minute, second):
  •   second_result = hour * 3600 + minute * 60 + second
  •   return second_result

  • result = get_time(2, 50, 17)
  • print(result)
blackboard bar

いちばん最初のdefって?

gaku04
meg08

これは関数ですよと宣言しているキーワードです。

英語で関数宣言するのが一般的で,今回は時間の計算だから,関数の名前をget_timeとしました。

def get_time(hour, minute, second):

次の行はこの関数で行われる計算を表しています。

second_result = hour * 3600 + minute * 60 + second

2時間50分17秒の場合,
2(hour) × 3600 = 7200秒
50(minute) x 60 = 3000秒
17(second) = 17秒

すべてたして2時間50分17秒は10,217秒と計算できますね。
そして,この関数が使われたときにはこの計算結果を返してね,という意味で,3行目を,

return second_result

この定義した関数を使うためには,下のように呼び出します。

get_time(2, 50, 17)

1行目で定めた関数に数をあてはめてあげればいいですね。

meg20

プログラムに沿って解説をまとめますね

プログラムの解説

  • # 「def」で関数であることを宣言。
  • # get_time(●,▲,■)と書いたら下の計算をしてね,という意味
  • def get_time(hour, minute, second):

  • # get_time (●,▲,■)と書かれたら,●×3600+▲×60+■の計算をし結果を変数「second_result」に代入する
  •   second_result = hour * 3600 + minute * 60 + second

  • # 最終的に「second_result」に代入された値を返す
  • #ここまでが関数の定義
  •   return second_result

  • # 関数「get_time」を使って計算した結果を変数「result」に代入する
  • result = get_time(2, 50, 17)

  • # resultに代入された値,つまり関数「get_time」の計算結果を表示
  • print(result)

blackboard bar

関数ができたら,あとはget_timeの()のなかの数値を変えるだけで,時間を秒に変換するプログラムができるってことね!

mana01

たしかに,いろいろな時間を秒に変換するたびにこのプログラムを書いてたんじゃ大変だから, 最初に数値が入力されたらこう計算する!って決めちゃうといいんだね。

gaku01
meg01

そうです,もし関数を使わずに3つの時間を秒に変換し,表示するプログラムを書いたら,このようなプログラムになりますね。

毎回処理を書く例

  • hour = 1
  • minute = 34
  • second = 55
  • second_result = hour * 3600 + minute * 60 + second
  • print(second_result)

  • hour = 6
  • minute = 40
  • second = 34
  • second_result = hour * 3600 + minute * 60 + second
  • print(second_result)

  • hour = 2
  • minute = 50
  • second = 17
  • second_result = hour * 3600 + minute * 60 + second
  • print(second_result)


blackboard bar
meg01

関数を使うとこんなにすっきりします。

関数を使った例

  • def get_time(hour, minute, second):
  •   second_result = hour * 3600 + minute * 60 + second
  •   return second_result

  • result = get_time(1, 34, 55)
  • print(result)
  • result = get_time(6, 40, 34)
  • print(result)
  • result = get_time(2, 50, 17)
  • print(result)


blackboard bar
meg12

関数は何か情報さえ渡せば勝手に処理してくれるロボットを作るイメージですね。

4_1_def

meg01

このときの2と5を引数(ひきすう),7を戻り値といいます。

関数が引っ張ってくる数字だから引数,関数から戻す値だから戻り値ですね。

mana01
meg04

引数や戻り値がないパターンもあるからイメージしてみましょう。

例えば,さっきの計算結果が10000秒以上なら「タイムオーバー!」それ以外は「クリア!」と表示する処理を実現する関数をつくってみましょう。

戻り値の無い関数の例

  • def check_time(hour, minute, second):
  •   second_result = hour * 3600 + minute * 60 + second
  •   if second_result >= 10000:
  •     print("タイムオーバー!")
  •   else:
  •     print("クリア!")

  • check_time(2, 50, 17)


blackboard bar

計算結果から数値を返すんじゃなく,「タイムオーバー!」か「クリア!」を表示するだけだから,戻り値(return)が無くていいんですね。

mana19
meg09

そうですね。今回は,計算結果を引数として入れて,その結果からプリントするだけの処理をするだけの関数ですね。

イメージはこんな感じです。

4_1_def2

戻り値(return)の無い関数はわかりましたが,引数の無い関数もあるんですか?

mana08
meg12

ありますよ。

たとえば,次のようなプログラムです

引数の無い関数の例

  • def display_clear():
  • # display_clear()という関数が呼び出されたら,「クリア!」と表示する
  •   print('クリア!')

  • sum = 6 + 5
  • # sumが10以上の数だったら, display_clearの関数を呼び出す(つまり「クリア!」と表示する)
  • if(sum >= 10):
  •   display_clear()


blackboard bar
meg04

イメージにするとこんな感じでしょうか。

4_1_def3

これだったら,わざわざ関数にする必要なくない?

余計にめんどうになった感じがする…

gaku07
meg15

この例だと特に関数にする必要もないと思うかもしれないですね。ただ,あえてクリアしたときの表示を関数にすることで,あとから「クリア!」ではなく「勝ち!」に変えたいと思ったときに,変更箇所がこの関数だけになって便利なことがあります。

複雑なプログラムをつくるときは,どの機能のまとまりを関数にするかを考えることが,よいプログラムをつくるためには必要です。

なるほど。まだ実感はないけど,関数の大切さはわかりました。

gaku11
meg16

それでは演習してみましょう。 次のプログラムは三角形の面積を求めたプログラムです。関数を用いた書き方にしてください。

演習1

  • 次のプログラムは3つの三角形の面積を求めたプログラムです。関数を用いた書き方にしましょう。
  • teihen = 2
  • takasa = 4
  • menseki = teihen * takasa / 2
  • print(menseki, "平方センチメートル")

  • teihen = 3
  • takasa = 8
  • menseki = teihen * takasa / 2
  • print(menseki, "平方センチメートル")

  • teihen = 6
  • takasa = 5
  • menseki = teihen * takasa / 2
  • print(menseki, "平方センチメートル")


blackboard bar
meg04

次の章では,スーパーのレジの機能を関数で実現してみましょう!

実習:レジ機能を作ろう

meg10

関数を利用して,レジ機能をつくって商品情報の入力,合計金額の表示,レシートの表示をするプログラムをつくってみましょう!!

meg01

レジには,どういう機能があると思いますか?

まずはフローチャートでレジの機能を整理してみましょう。

商品のバーコードを何度か読み取って,計算して,合計金額出して,おつり計算して・・・

gaku04

こんな感じでしょうか?

6-2_1

mana10
meg20

そうそう,それでは順にプログラムを組み立てていきましょう。

meg08

このページの右下にある「プログラム」ボタンを押し,「レジエディタ」を選択しましょう。

6-2_2

今回はこの専用エディタを使って,疑似的なレジ機能をプログラムしていきます。

プログラムが完成するとこんな風に動くようになりますよ。

meg01

まずは商品の名前,個数,金額,税率の情報を読み取る動きからつくっていきますが,すべて自分でプログラムを書いて設計するのはなかなか難しい内容です。 しっかり読んで,プログラムの構造を理解することに注力してください。

meg01

レジ機能をつくるのに必要だけれども,今回の講座では扱わない部分については,最初からエディタに入っています。消さないようにしてください。

6_regi_code

購入する商品をリストに登録する関数

  • def add(name, num, price, tax):
  •   print('商品名: ' + name)
  •   print('個数: ' + str(num))
  •   print('金額: ' + str(price))
  •   print('税率: ' + str(tax))

  •   # データをリストにしてitemsに追加していく
  •   items.append([name, num, price, tax])

blackboard bar
meg15

説明しますね。

読み取る情報をそれぞれ,name(名前), num(個数), price(値段), tax(税率)とし,

バーコードを読み取ったらその情報をitemsと名付けたリストに追加していくというプログラムですね。

このプログラムをエディタにコピーしましょう。

meg22

プログラムのコピーができたら,レジに購入する商品を追加しましょう。

今回バーコードを読み取る仕組みはないので,読み取ったつもりで情報をエディタに入力していきます。

次のように名前,個数,値段,税率を入力して「追加」を押すと,add関数が呼び出されて,読み取ったつもりの商品がリストに追加されます。「追加」を押して,正しくプログラムが動いているかどうか,確認しましょう。

4_2_editor

あれ…僕が書いたプログラムだとこんなエラーが出てきたんだけど…

Traceback…? NameError…?

4_2_error

gaku07
meg11

プログラムに問題があれば,それに合わせたエラーメッセージが表示されます。

下の四角で囲んだ部分のプログラムをみてください。

今回の場合は,インデントを入れていないので,関数の外に記述されたものという扱いになっているため,エラーが出ているんですよ。

4_2_add_error

プログラムを書くときにはインデントに気をつけなきゃいけないんだったね!

mana04
meg08

「一覧表示」をクリックすることで今入力されている商品をみることができます。また「リセット」をクリックすることで,入力したものを消すこともできます。

6_regi_buttons

meg08

次に,合計値を求める関数を作ります。

購入する商品の合計金額を計算する関数

  • def sum():
  •   print('sum')
  •   total = 0
  •   for item in items:
  •     num = item[1]
  •     price = item[2]
  •     tax = item[3]
  •     total = total + int(price * num * (1 + tax * 0.01))
  •   print(total)
  •   return total
blackboard bar

sumが合計を求める関数ってことですね。

itemsに追加されたデータから,numpricetaxを取り出して計算しているってことか。

mana10

途中のint(price * num * (1 + tax * 0.01))ってなんですか?

gaku07
meg22

消費税の計算をすると小数点になる場合もありますよね。

その場合は切り捨てにするので, int()という関数で整数に変換しています。

meg12

「合計表示」を押すと,sum関数が呼び出されて,合計金額が表示されます。

正しく計算されるか確認してみましょう。

4_2_sum

合計が表示されました!

gaku11
meg12

次は支払いからおつりを計算する関数です。

支払いからおつりを計算する関数(amount: 支払い,戻り値: おつり)

  • def pay(amount):
  •   print('pay: ' + str(amount))
  •   change = amount - sum()
  •   if(change < 0):
  •     print("代金がたりません")
  •   print("おつり" + str(change) + "円")
  •   return change


blackboard bar
meg22

「支払い」を押すと,pay関数が呼び出されて,おつりの計算がされます。

預かり金額をエディタに入力して「支払い」を押し,正しくおつりが表示されるか確認しましょう。

4_2_pay2

meg19

次はレシートを表示するための関数です。

レシートを表示する関数

  • def show_receipt():
  •   print('show_receipt:' + str(amount))
  •   for item in items:
  •     name = item[0]
  •     num = item[1]
  •     price = item[2]
  •     tax = item[3]
  •     print(name, num, price, "円", tax)

blackboard bar
meg08

「レシート表示」を押すと,show_receipt関数が呼び出されて,レシートが表示されます。「追加」した商品や金額がすべて表示されることを確認しましょう。

4_2_receipt_3

ここでは簡単な商品一覧を表示する機能になっています。次の応用編で,もっとレシートっぽくなります。

どうでしょうか?レジの機能は実現できましたか?

できました!

gaku02

レジ機能:レシート表示(チャレンジ問題)

meg04

応用課題に取り組みたい人は,レシートをもっと詳しく再現してみたり,現金払いのときのおつりのお札や枚数の計算をするプログラムを組み込んだりしてみましょう!

meg23

レシートの例を貼っておきますね。

4_2_receipt_2

シンプルなレシートですね。

mana12
meg08

コンビニのレシートなど改めてみると,いろんな情報が記載されているのがわかって面白いですよ。

さて,レシートを表示するプログラムの例を紹介します。

レシート表示(amount: 支払い金額)

  • def show_receipt(amount):
  •   print("[領収書]")
  •   print("夕陽ケ丘ストア")
  •   total_price = 0
  •   count = 0
  •   total_tax = 0

  •   # 商品毎に繰り返し
  •   for item in items:
  •     name = item[0]
  •     num = item[1]
  •     price = item[2]
  •     tax = item[3]
  •     total_price = total_price + price * num
  •     count = count + num
  •     total_tax = total_tax + price * num * tax * 0.01
  •     print(name)
  •     print(" ¥" + str(price), str(num)+"点", "¥" + str(price * num))

  •   print("-------")
  •   print("小計 ", str(count) + "点", "¥" + str(total_price))
  •   print("外税計 ", " ¥" + str(int(total_tax)))
  •   print("合計 ", " ¥" + str(int(total_price + total_tax)))
  •   print("お預かり", " ¥" + str(int(amount)))
  •   print("おつり ", " ¥" + str(int(amount - total_price - total_tax)))


blackboard bar

できました!

でも,複雑になってきましたね。

mana12

レジ機能:おつり(チャレンジ問題)

meg01

次は,おつりを応用していきましょう。

え,さっきおつりの金額をだしましたよ?

gaku07
meg12

最近のレジは,おつりを自動で出してくれるところもありますよね?

支払い関数を千円札が何枚,500円玉が何枚と計算できる機能に進化させてみましょう。

そっか,たしかにおつりを自動で出すためにもプログラムで計算しないと!

mana09

改めて考えると,そういう便利なことも誰かがプログラミングしてくれているんですね。

gaku16
meg08

ここでは関数というより,アルゴリズムを考える方が大変かもしれないですね。

どういうロジックで処理をするとそれぞれのお金の枚数を計算できるか考えてみてください。

どうやって考えればいいんだろう…

gaku12

普通は一番大きな10000円札はおつりにはならないですね。

5000円札は,おつりが5000円以上のときに1枚使いますね。

その後,1000円札が何枚返すべきか計算して,

その後,500円玉の枚数,と続いていくのかしら。

mana12
meg10

例えば3422円のおつりの場合,どう考えますか?

1000円札を3枚返すと,残りは422円。

あとは100円玉を4枚返して,残りは22円。

10円玉を2枚と1円玉を2枚ですね。

gaku07
meg14

そうそう,その調子ですよ。

大きいお札から計算していけば良さそうですね。

わかった!

大きなお札からわり算して,そのあまりを次に大きなお札でわり算してを繰り返していけばできそう!

mana10
meg01

そうですね。実際のプログラムは次のようになります。

支払いとおつり表示

  • # 支払い
  • def pay(amount):
  •   change = amount - sum()
  •   # 預り金を保存
  •   if(change < 0):
  •     print("代金がたりません")
  •   # おつりの枚数を表示
  •   show_change(amount - sum())
  •   return change

  • # おつり表示
  • def show_change(change):
  •   print(change)
  •   change_left = change
  •   kinds = [10000, 5000, 1000, 500, 100, 50, 10, 5, 1]
  •   for kind in kinds:
  •     count = change_left // kind # わり算の商
  •     change_left = change_left % kind # わり算の余り
  •     if(kind >= 1000):
  •       print(str(kind) + "円札:" + str(count) + "枚")
  •     else:
  •       print(str(kind) + "円玉:" + str(count) + "枚")

blackboard bar

わあできた!

gaku11

なるほど,リストに10000円札から1円玉までの数字をいれて,

繰り返しでわり算しているんですね。

わり算も「商」と「あまり」を使っているのがわかりました!

mana23
meg01

だいぶ複雑になってきましたね。でも実際は小学校で習う算数の計算を使っているだけなので,ゆっくり確認してみてください。

次はさらに応用としてプログラミングで計算する演習にチャレンジしてみましょう!

関数を使いこなそう:再帰関数

meg15

関数は,数学の問題を解くときにも使われることが多いですよ。

計算するとき?電卓とは違うのかな?

gaku10

そういえば,円周率はプログラムを組んで計算しているとか聞いたことがあります。

mana02
meg01

そうですね。円周率は小数点以下50兆桁まで計算されているそうですよ。皆さんがこの教材をみている間にさらに更新されているかもしれませんね。

このように,電卓を使っても人間がやりきれないような計算もプログラミングで解くことができます。

たしかに!それは人手ではできない。

gaku04
meg08

手はじめに,1〜1000の数字をたしていくプログラムをつくってみましょう!

1+2+3+....+1000ってことですね。

mana12
meg15

はいそうです。

プログラムは次のようになります。

nまでの自然数の和を計算する関数

  • def ruikei(n):
  •   total = 0
  •   for i in range(1, n + 1):
  •     total = total + i
  •   return total

  • print(ruikei(1000))

blackboard bar

ruikeiという関数が,引数に入れた数字までの和を繰り返しを使って計算していますね。

mana10
meg22

そうです。そして,次のように書くこともできます。

(ブラウザの制限でnを大きくしすぎるとエラーになります。反応がなくなってしまったらブラウザを再起動してください。)

  • # nまでの自然数の和を計算する関数(再帰)
  • def ruikei(n):
  •   if(n < 1):
  •     return 0
  •   return n + ruikei(n - 1)

  • print(ruikei(1000))
blackboard bar

あれ?関数のなかで関数を呼んでる?

さっきのプログラムよりは少し短く書けてますね。

gaku36
meg10

はい。ちょっと難しいですが,落ち着いて1つずつ考えてみましょう。

ruikei(n) → n + ruikei(n - 1)

ruikei(n - 1) → n - 1 + ruikei(n - 2)

ruikei(n - 2) → n - 2 + ruikei(n - 3)

と続きます。

n = 3の場合

ruikei(3) → 3 + ruikei(2)

ruikei(2) → 2 + ruikei(1)

ruikei(1) → 1 + ruikei(0)

ruikei(0) → 0

引数が1つずつ減った関数がどんどん呼ばれていくってことですね?

mana15
meg12

はい。そうなります。図解すると以下のようになります。

6-3_1

なるほど!

gaku39
meg01

それでは,次は自然数nを引数に,1〜nのすべての積を計算する関数をつくってみましょう!

nの階乗ですね。

階乗を求める関数

  • def kaijo(n):
  •   if(n <= 1):
  •     return 1
  •   return n * kaijo(n - 1)

  • print(kaijo(10))
blackboard bar

なるほどできました。

gaku01
meg01

この関数には名前がついていて,「再帰関数」といいます。難しかった人やさらに詳しく知りたい人は調べてみてくださいね。

meg01

こんな風に,計算機でも面倒な計算や,複雑な計算式をコンピュータで実現すると便利になる場合もあります。

今回の合計を求める関数は等差数列の和の公式を使うともっと計算を簡単にすることもできます。

プログラミングアルゴリズムを考えていくのも楽しいですよ。

unfold_more 拡大