値を返す関数
計算した答えを,関数に持ち帰らせます.
前の章,関数を作れるようになりました.引数を使えば, 外から関数の中へ値を渡すこともできました.
では逆はどうでしょうか.関数に計算をしてもらって,
その答えを受け取りたいことがあります.
「BMI を計算して」「この 2 点の距離を教えて」「次に塗る色を決めて」.
こういうとき必要になるのが,今回の return(リターン)です.
return で返す値を戻り値(もどりち)といいます.
教科書によっては「返り値(かえりち)」「リターン値」とも呼びますが,
どれも同じもので,英語の return value の訳が定まっていないだけです.
この教材では戻り値と呼びます.
returnで,関数から値を持ち帰らせられる- 戻り値を変数に入れる・そのまま使う・
printする,が使い分けられる returnを実行すると関数がそこで終わることがわかる- 戻り値のない関数が
Noneを返していることがわかる - 座標・距離・色を返す関数を作って,タートルの絵に使える
mathモジュールの関数が使える(度とラジアンの違いに気をつけられる)- 関数を組み合わせて,プログラム全体を見通しよく組み立てられる
14.1 関数の入力と出力
関数は,箱だと思ってください. 左から材料を入れると,右から製品が出てきます.
第 13 章で作った関数は,入口だけがあって出口が無い箱でした.
square(80) と呼ぶと絵が描かれますが,
こちらに何かが返ってくるわけではありません.
今回はここに出口をつけます.
| 関数の種類 | 例 | 呼び方 |
|---|---|---|
| 入力も出力もない | def hello(): | hello() |
| 入力だけ(第 13 章) | def square(size): | square(80) |
| 出力だけ | def pi(): …… return 3.14 | x = pi() |
| 入力も出力もある(今回の主役) | def area(w, h): …… return w * h | x = area(3, 4) |
print("あ")は入力だけ.画面に出すのが仕事で,こちらには何も返しません.input()は出力だけ.引数は要らず,打ち込まれた文字を返します.第 9 章でs = input()と書いたのは,まさに戻り値の受け取りでした.max(3, 8)・len("あいう")・int("42")は入力も出力もある関数です.
int(input()) という第 9 章からのお決まりの書き方も,
「input の戻り値を int の引数にする」という意味だったのです.
14.2 return — 値を持ち帰らせる
14.2.1 return の書き方
関数の中で return と書き,そのうしろに返したい値を書きます.
それだけです.
# 横 w・縦 h の長方形の面積を返す
def area(w, h):
answer = w * h
return answer
s = area(3, 4)
print("面積は", s, "です")
print(area(10, 20))
コンソールに 面積は 12 です と 200 が出ます.
area(3, 4) という書き方そのものが,12 という値に化ける
と考えてください.
def 関数の名前(仮引数):
中身の命令
return 返したい値
変数 = 関数の名前(実引数)
return の行を見れば分かる,という考え方です.
そのぶん,関数の上に「何を返す関数か」をコメントで書いておくと親切です.
14.2.2 戻り値の使い道は 4 つ
返ってきた値は「ただの数」です.数を書いてよい場所なら,どこにでも書けます.
# 2 倍にして返す
def double(x):
return x * 2
# 1. 変数に入れる
a = double(5)
print(a)
# 2. そのまま print に渡す
print(double(5))
# 3. 計算の途中で使う
print(double(5) + double(3) + 1)
# 4. 別の関数(自分自身でもよい)の引数にする
print(double(double(5)))
10・10・17・20 と表示されます.
3 番目は 10 + 6 + 1,4 番目は double(10) ですね.
area(3, 4) # 12 を返しているが,誰も受け取っていない
print("面積は 12 です")
s = area(3, 4) のように変数に入れるか,
print(area(3, 4)) のようにその場で使うか,必ずどちらかにしてください.
底辺 b・高さ h の三角形の面積を返す関数を作ります.
____ を埋めてください.
三角形の面積は「底辺 × 高さ ÷ 2」です.
# 底辺 b・高さ h の三角形の面積を返す
def triangle_area(b, h):
____ b * h / 2
s = triangle_area(10, 6)
print("面積は", ____, "です")
# 変数に入れずに,そのまま使ってもよい
print(____(8, 5))
14.2.3 return すると,関数はそこで終わる
return には,もうひとつ大事な働きがあります.
return を実行した瞬間に,関数はそこで終わります.
その先に命令が書いてあっても,実行されません.
def test():
print("ここは実行される")
return 1
print("ここは実行されない")
x = test()
print("戻ってきた値:", x)
これは欠点ではなく,むしろ便利な性質です.
if と組み合わせると,こう書けます.
# 点数から合否を返す
def judge(score):
if score >= 60:
return "合格"
else:
return "不合格"
print(judge(80))
print(judge(45))
print(judge(60))
return "合格" が実行されれば,そこで関数は終わるので,
else を書かずに次のようにも書けます.どちらでも構いません.
def judge(score):
if score >= 60:
return "合格"
return "不合格" # 60 点未満のときだけここに来る
return がどの道を通っても実行されるかを確かめてください.
次の関数は score が 60 未満のとき,
return に一度も出会わずに終わってしまいます.
def judge(score):
if score >= 60:
return "合格"
# 60 未満のとき,何も返さない
judge(30) の値は None(後述)になり,
print すると None と表示されて「あれ?」となります.
14.2.4 返す値が無い関数と None
第 13 章で作った関数には return がありませんでした.
では square(80) の「値」は何なのでしょうか.確かめてみましょう.
def hello():
print("こんにちは")
x = hello()
print("hello() の値:", x)
print(type(x))
None(ノン)と表示されます.
None は「値が無い」ということを表す特別な値です.
return を書かなかった関数は,
Python が自動的に None を返しているのです.
このことを知らないと,こんな失敗をします.
表示する関数を,さらに print で囲んでしまうという失敗です.
# 表示するだけの関数(return が無い)
def show_stars():
print("*****")
print(show_stars()) # よくある勘違い
***** の次の行に,None が出てしまいます.
まず show_stars() が実行されて ***** が表示され,
そのあと,返ってきた None を外側の print が表示するからです.
直し方は簡単で,print を外して show_stars() と書くだけです.
print 自身も,画面に出すだけで何も返さない関数です.
ですから print(print("あ")) と書くと,
あ の次の行に None が出ます.
「None が 1 行よけいに出る」ときは,
戻り値の無い関数を print で囲んでいないかを疑ってください.
None を返す
というルールになっています.
None は「値が無い」ことを表す特別な値で,
0 や ""(空文字)とは別ものです.
14.2.5 戻り値はいくつまで?
引数はいくつでも書けました.戻り値はどうでしょうか. Python では,カンマで区切っていくつでも並べて返せます.
# 小さいほう・大きいほうの順に並べて返す
def min_max(a, b):
if a < b:
return a, b
else:
return b, a
small, big = min_max(7, 3)
print("小さいほう:", small)
print("大きいほう:", big)
受け取る側も small, big = ... とカンマで並べます.
見た目は 2 つ返しているようですが,正確にいうと
「2 つの値をひとまとめにしたタプルという 1 個の値」を返しています.
つまり「戻り値はひとつ」という原則は Python でも変わっていません.
書き方が楽になっているだけです.
return x, y として使います.
14.3 いろいろな種類の値を返す
Python では型を書かないので,返せる値の種類に制限がありません.
数でも,文字でも,真偽値でも,同じ return で返せます.
「相性占い」を作りながら確かめましょう.
14.3.1 数を返す
# 2 つの名前から相性(0〜99)を計算して返す
def aisho(name1, name2):
total = 0
for c in name1 + name2:
total = total + ord(c)
return total % 100
print("相性は", aisho("はなこ", "たろう"), "です")
print("相性は", aisho("因島", "花子"), "です")
for c in name1 + name2: は,
2 つの名前をつないだ文字列から1 文字ずつ取り出す繰り返しです.
ord(c) はその文字に割り当てられている番号を返します
(ord("A") は 65).
文字を数に変えて全部足し,% 100 で 0〜99 に収めているわけです.
占いですから,中身に深い意味はありません.
14.3.2 文字を返す
数のままでは味気ないので,判定したことばを返す関数にしてみます.
def aisho(name1, name2):
total = 0
for c in name1 + name2:
total = total + ord(c)
return total % 100
# 点数からことばを返す
def judge(name1, name2):
if aisho(name1, name2) > 70:
return "ばっちり"
elif aisho(name1, name2) > 40:
return "そこそこ"
else:
return "努力しだい"
print("はなこさんとたろうさんの相性は", judge("はなこ", "たろう"))
print("因島さんと花子さんの相性は", judge("因島", "花子"))
judge の中で aisho を呼んでいることに注目してください.
戻り値のある関数どうしも,組み合わせられます.
14.3.3 真偽値(True・False)を返す
第 5 章の if で使った score >= 60 のような式は,
True(真)か False(偽)という値になるのでした.
これも return で返せます.
def aisho(name1, name2):
total = 0
for c in name1 + name2:
total = total + ord(c)
return total % 100
# 相性がよければ True,そうでなければ False を返す
def is_good(name1, name2):
if aisho(name1, name2) > 60:
return True
else:
return False
# 戻り値を if の条件にそのまま書ける
if is_good("はなこ", "たろう"):
print("はなこさんとたろうさんは相性ばっちり!")
else:
print("はなこさんとたろうさんは努力しだい...")
if is_good("因島", "花子"):
print("因島さんと花子さんは相性ばっちり!")
else:
print("因島さんと花子さんは努力しだい...")
if の条件には「最後に True か False になるもの」を
書く決まりでした.
ですから if is_good("はなこ", "たろう"): のように,
真偽値を返す関数をそのまま条件に書けます.
is_(〜である)や has_(〜を持つ)で
始まる名前をつけるのが習慣です.
is_good・is_even(偶数か)・is_hit(当たったか).
こうしておくと if is_hit(x, y): が英語の文のように読めます.
is_good(...) は,中身がすでに True か False です.
if is_good(...) == True: と書く必要はありません
(書いても動きますが,くどい書き方です).
さらに,次のように書けば if すら要りません.
def is_good(name1, name2):
return aisho(name1, name2) > 60
数が偶数なら True,奇数なら False を返す関数を作り,
if の条件に使います.
偶数とは「2 で割った余りが 0」の数でした(第 7 章の剰余).
____ を埋めてください.
# n が偶数なら True,奇数なら False を返す
def is_even(n):
if n % 2 == ____:
return ____
else:
return ____
for i in range(6):
if ____(i):
print(i, "は偶数")
else:
print(i, "は奇数")
14.4 タートルで使う
戻り値は,絵を描くときにも大活躍します. 「どこに描くか」「どれだけ進むか」「何色にするか」を 計算して返す関数を用意しておくと,本文がとても短くなります.
14.4.1 座標を計算して返す関数
中心から半径 r,角度 deg の場所の座標を返す関数を作ります.
座標は x と y の 2 つなので,14.2.5 節で習った「並べて返す」を使います.
from turtle import *
import math
# 中心から半径 r・角度 deg の位置の座標を返す
def point_on_circle(r, deg):
x = r * math.cos(math.radians(deg))
y = r * math.sin(math.radians(deg))
return x, y
ht()
for i in range(12):
x, y = point_on_circle(150, i * 30)
pu()
goto(x, y)
pd()
pencolor("royalblue")
dot(18)
done()
本文の側は x, y = point_on_circle(150, i * 30) の 1 行だけで,
「半径 150 の円周上の,30 度ずつの場所」を手に入れています.
三角関数の計算は関数の中に押し込めてあるので,
読むときに気にしなくてよくなりました.
面倒な計算を関数に隠すのも,関数の大事な働きです.
同じ point_on_circle を使って,点を線でつないだり,
半径を少しずつ変えたりすると,まったく違う絵になります.
変えたのは呼び方だけで,関数の中身は一文字も直していません.
14.4.2 距離を返す関数
2 点の距離は,三平方の定理(ピタゴラスの定理)で求められます.
横の差と縦の差をそれぞれ 2 乗して足し,平方根をとります.
Python では ** が「べき乗」,
math.sqrt が「平方根」です.
from turtle import *
import math
# (x1, y1) と (x2, y2) の距離を返す
def line_length(x1, y1, x2, y2):
yoko = x2 - x1
tate = y2 - y1
return math.sqrt(yoko ** 2 + tate ** 2)
ht()
pensize(3)
pencolor("royalblue")
pu()
goto(-150, -80)
pd()
goto(120, 110)
nagasa = line_length(-150, -80, 120, 110)
print("線の長さ:", nagasa)
pu()
goto(-60, 40)
pencolor("crimson")
write(round(nagasa, 1), font=("Arial", 22, "bold"))
done()
round(x, 1) は「小数第 1 位で四捨五入する」命令です.
round(x) とだけ書くと整数に丸めます.
計算結果をそのまま表示すると 330.15148038438356 のように
長くなるので,表示のときは丸めましょう.
14.4.3 色を決めて返す関数
返すのは数だけではありません.色の名前(文字)を返す関数も作れます.
from turtle import *
# i 番目に使う色を返す
def pick_color(i):
if i % 3 == 0:
return "crimson"
elif i % 3 == 1:
return "seagreen"
else:
return "royalblue"
pensize(3)
ht()
for i in range(12):
pencolor(pick_color(i))
fd(140)
lt(150)
done()
pencolor(pick_color(i)) の 1 行で色が変わっていく.pencolor(pick_color(i)) は,
pick_color(i) が返した色の名前を,
そのまま pencolor の引数にしています.
戻り値をほかの関数の引数にする,14.2.2 節の 4 番目の使い方です.
i 番目の正方形の 1 辺の長さを返す関数を作り,
だんだん小さくなる正方形を描きます.
____ を埋めてください.
from turtle import *
pensize(2)
ht()
# i 番目の正方形の 1 辺の長さを返す
def pick_size(i):
____ 160 - i * 15
# 1 辺 size の正方形を描く(第 13 章で作った関数)
def square(size):
for j in range(4):
fd(size)
lt(90)
pu()
goto(-80, -80)
pd()
for i in range(8):
square(____(i))
lt(10)
done()
14.5 math を使った計算
math.sqrt や math.cos を,ここまで説明なしに使ってきました.
これらは math モジュールに入っている関数です.
第 13 章の最後に出てきた「ライブラリ」のひとつで,
数学の計算をする関数が集められています.
import math # 数学の道具箱を開ける(1 行目に書く) print(math.sqrt(2)) # math. を付けて呼ぶ
from turtle import * は「箱の中身を全部取り出して,
そのままの名前で使えるようにする」書き方でした.
import math は「箱ごと持ってくる」書き方で,
使うときに math. を付けます.
math.sqrt と書けば「math の中の sqrt」という意味で,
どこから来た関数かがひと目で分かります.
| 書き方 | 意味 | 例 |
|---|---|---|
math.sqrt(x) | 平方根 | math.sqrt(9) → 3.0 |
math.pi | 円周率 π(関数ではなく値) | 3.141592653589793 |
math.sin(x) | サイン(x はラジアン) | |
math.cos(x) | コサイン(x はラジアン) | |
math.tan(x) | タンジェント(x はラジアン) | |
math.radians(d) | 度をラジアンに直す | math.radians(180) → 3.1415… |
math.degrees(r) | ラジアンを度に直す | math.degrees(math.pi) → 180.0 |
math.floor(x) | 切り捨て(小さいほうの整数へ) | math.floor(3.7) → 3 |
math.ceil(x) | 切り上げ(大きいほうの整数へ) | math.ceil(3.2) → 4 |
math.hypot(a, b) | 斜辺の長さ(三平方の定理) | math.hypot(3, 4) → 5.0 |
abs(x)(絶対値)・round(x, n)(四捨五入)・
max(a, b)・min(a, b)・len(s) は,
math の外にある組み込み関数です
(第 13 章 13.6.4 節).
import が要らないかわりに,math. も付けません.
math.sqrt には math. が要り,
abs には要らない.この違いは
「どこの箱に入っている関数か」の違いです.
14.5.1 度とラジアンに気をつける
math.sin・math.cos・math.tan に渡す角度の単位は
度ではなくラジアンです.
タートルの lt(90)・rt(90) は度なので,
うっかり同じ感覚で書くと,エラーも出ないまま間違った絵になります.
import math
print("math.sin(90) =", math.sin(90))
print("math.sin(radians(90)) =", math.sin(math.radians(90)))
print("math.cos(0) =", math.cos(0))
print("math.cos(radians(60)) =", math.cos(math.radians(60)))
print("180 度は", math.radians(180), "ラジアン")
print(math.pi, "ラジアンは", math.degrees(math.pi), "度")
math.sin(90) は 0.894… という,
まるで見当違いの値になります.エラーは出ません.
90 度のサインは 1 のはずですから,これはバグです.
三角関数に角度を渡すときは,必ず math.radians() をかぶせる.
そう覚えてください.
| 度 | ラジアン | 書き方 |
|---|---|---|
| 0 度 | 0 | math.radians(0) |
| 30 度 | π/6 ≒ 0.524 | math.radians(30) |
| 90 度 | π/2 ≒ 1.571 | math.radians(90) |
| 180 度 | π ≒ 3.142 | math.radians(180) |
| 360 度 | 2π ≒ 6.283 | math.radians(360) |
14.5.2 sin で波を描く
math.sin を「x の場所での波の高さを返す関数」として使うと,
タートルで波が描けます.
math.sin が返すのは -1 から 1 の値なので,
80 倍して見える大きさにしています.
from turtle import *
import math
# 横位置 x のところの波の高さを返す
def wave_y(x):
return 80 * math.sin(math.radians(x * 2))
ht()
pensize(3)
pencolor("teal")
pu()
goto(-280, wave_y(-280))
pd()
for i in range(141):
x = -280 + i * 4
goto(x, wave_y(x))
done()
math.radians(x * 2) の 2 を変えると波の細かさが,
80 を変えると波の高さが変わります.
math.cos に変えるとどうなるか,
math.sin(radians(x)) + math.sin(radians(x * 3)) のように
2 つ足すとどうなるかも試してみてください.
星(五芒星)の i 番目の頂点の座標を返す関数を作り,
線でつないで星を描きます.
頂点は 144 度ずつ離れているのでしたね(第 2 章).
____ を埋めてください.
math.cos と math.sin に渡す前に,何をかぶせるか忘れずに.
from turtle import *
import ____
pensize(3)
pencolor("gold")
ht()
# 星の i 番目の頂点の座標を返す
def star_point(i):
deg = 90 + i * ____
x = 160 * math.cos(math.____(deg))
y = 160 * math.sin(math.____(deg))
return x, y
x, y = star_point(0)
pu()
goto(x, y)
pd()
for i in range(1, 6):
x, y = star_point(i)
goto(x, y)
done()
14.6 関数を組み合わせて組み立てる
第 13 章で,図形を部品に分けて組み立てました. 戻り値があると,計算する部分も部品に分けられます. 「西暦和暦変換プログラム」で見てみましょう.
まず,関数に分けずに書くと,こうなります. 短いプログラムなので,これでも読めます.
print("西暦和暦変換プログラムを開始します")
print("西暦を入力してください")
year = int(input())
if year >= 2019:
wareki = "令和" + str(year - 2018)
elif year >= 1989:
wareki = "平成" + str(year - 1988)
elif year >= 1926:
wareki = "昭和" + str(year - 1925)
else:
wareki = "不明"
print(year, "年は", wareki, "年です")
print("西暦和暦変換プログラムを終了します")
これを「入力する」「変換する」「表示する」の 3 つに分けます. 変換する部分だけが戻り値を持つところに注目してください.
# 西暦を入力してもらって返す
def input_year():
print("西暦を入力してください")
return int(input())
# 西暦を和暦の文字に変えて返す
def to_wareki(year):
if year >= 2019:
return "令和" + str(year - 2018)
elif year >= 1989:
return "平成" + str(year - 1988)
elif year >= 1926:
return "昭和" + str(year - 1925)
else:
return "不明"
# 結果を表示する(戻り値は無い)
def show_result(year, wareki):
print(year, "年は", wareki, "年です")
# 変換をひとまとめにする
def convert_year():
year = input_year()
wareki = to_wareki(year)
show_result(year, wareki)
print("西暦和暦変換プログラムを開始します")
convert_year()
print("西暦和暦変換プログラムを終了します")
2005 と書いてあります.
実行すると,この行が input() に渡されます.
数を変えて,令和・平成・昭和のそれぞれを試してください.
| 関数 | 入力(引数) | 出力(戻り値) | 役割 |
|---|---|---|---|
input_year() | なし | 西暦(数) | 人に聞く |
to_wareki(year) | 西暦(数) | 和暦(文字) | 計算する |
show_result(year, wareki) | 西暦と和暦 | なし(None) | 見せる |
convert_year() | なし | なし | 3 つを順に呼ぶ |
- 「計算する」関数は
printもinputもしません.だからそのままテストできます(14.7 節). - 画面への出し方を変えたくなっても,直すのは「見せる」関数だけです.
- 入力をキーボードからファイルに変えても,「計算する」関数はそのまま使えます.
身長と体重から BMI を計算して判定するプログラムです. 計算する関数と判定する関数に分かれています. BMI は「体重 ÷ (身長 m × 身長 m)」で求めます. ____ を埋めてください.
# 身長(cm)・体重(kg) から BMI を計算して返す
def get_bmi(height, weight):
m = height / 100
____ weight / (m * m)
# BMI から判定のことばを返す
def judge_bmi(bmi):
if bmi < 18.5:
return "やせぎみ"
elif bmi < 25:
return "ふつう"
else:
____ "ふとりぎみ"
bmi = ____(170, 62)
print("BMI は", round(bmi, 1))
print("判定は", ____(bmi))
14.7 関数をテストする
戻り値のある関数には,うれしい性質があります. 正しく動いているかを,機械的に確かめられるのです. これをテストといいます.
例として,累乗(base を exponent 回かけた数)を
計算する関数を作ります.
# base を exponent 回かけた数を返す
def power(base, exponent):
answer = 1
for i in range(exponent):
answer = answer * base
return answer
print("power(2, 2) =", power(2, 2))
print("power(2, 3) =", power(2, 3))
print("power(2, 4) =", power(2, 4))
print("power(3, 3) =", power(3, 3))
毎回キーボードから入力して確かめるのは大変ですし, どのテストをやったか忘れてしまいます. さらに,プログラムを 1 行直しただけでも, どこが動かなくなるかは予測できません. だから,テストはプログラムに書いて自動化するのが正解です. 上のように並べて呼び出して表示するだけでも,立派なテストです.
14.7.1 テストも関数にする
print の行が長くて,書き換えるのが大変です.テストも関数にしましょう.
def power(base, exponent):
answer = 1
for i in range(exponent):
answer = answer * base
return answer
# 1 件ぶんのテストを表示する
def test(base, exp):
print("power(", base, ",", exp, ") =", power(base, exp))
test(2, 2)
test(2, 3)
test(2, 4)
test(3, 3)
14.7.2 期待値を書いて,合否まで出す
これでも「答えが合っているか」は自分の目で確かめなければなりません. プログラムに答え(期待値)も書いておき, 合っているかどうかまで表示させましょう.
def power(base, exponent):
answer = 1
for i in range(exponent):
answer = answer * base
return answer
# expected は「こうなるはず」という答え
def test(base, exp, expected):
answer = power(base, exp)
if answer == expected:
result = "PASS"
else:
result = "FAIL"
print("power(", base, ",", exp, ") =", answer, " 判定:", result)
test(2, 2, 4)
test(2, 3, 8)
test(2, 4, 16)
test(3, 3, 27)
test(5, 0, 1) # 0 乗は 1
test(2, 1, 2)
すべて PASS と出れば安心です.
このあと power の中身を書き換えたときも,
このプログラムを 1 回実行するだけで,
壊れていないかが一瞬で分かります.
test(5, 0, 1)(0 乗),test(0, 3, 0)(0 のべき乗),
test(2, 1, 2)(1 乗)のように,
「0 のとき」「1 のとき」「いちばん小さいとき」を必ず試してください.
バグの多くはここに隠れています.
14.8 この章で出てきた書き方
| 書き方 | 意味 |
|---|---|
return 値 | その値を戻り値として返し,関数はそこで終わる |
return a, b | 2 つ以上の値を並べて返す |
x = f(…) | 戻り値を変数に入れる |
print(f(…)) | 戻り値をそのまま表示する |
g(f(…)) | 戻り値を別の関数の引数にする |
if f(…): | 真偽値を返す関数を条件に使う |
None | 「値が無い」ことを表す値.return の無い関数が返す |
import math | 数学の関数の入った箱を持ってくる |
math.sqrt(x) | 平方根.math. を付けて呼ぶ |
math.radians(d) | 度をラジアンに直す.sin・cos に渡す前に必ず使う |
round(x, 1) | 小数第 1 位で四捨五入する |
ord(c) | 文字に割り当てられた番号を返す |
| 症状 | 原因と直し方 |
|---|---|
SyntaxError: 'return' outside function | 関数の外で return を書いている.字下げを見直す |
None と表示される | return を書き忘れている/if のある道筋で return に届いていない/表示するだけの関数を print(…) で囲んでいる |
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int' | None を返す関数の値で計算しようとしている.その関数に return があるか確かめる |
NameError: name 'math' is not defined | import math を書き忘れている |
NameError: name 'sqrt' is not defined | math. を付け忘れている |
| 計算結果がおかしい(エラーは出ない) | sin・cos に度をそのまま渡している.math.radians() をかぶせる |
| 値が変わらない・使われていない | f(3) と呼んだだけで,戻り値を受け取っていない |
return のうしろが実行されない | 仕様どおり.return で関数は終わる |
演習
以下の演習には出発点となるプログラムが入っています. 「▶ この演習を開く」で右側に読み込み,それを発展させて完成させてください.
test 関数まで書いてみてください.
生まれ年(西暦)から今年の年齢を計算して返す関数
get_age(year) があります.
テストされていることを確かめてから,発展させてください.
- 「今年」を
2026と直書きしているのを,引数で渡せるようにする - 生まれ年と今年から,学年(小 1・中 2・大 3 など)を返す関数を足す
- キーボードから生まれ年を入力できるようにする
- 1900 年より前など,おかしな入力のときは
-1を返す
税抜き価格から税込み価格(消費税 10 %)を計算して返す関数
get_with_tax(price) があります.
テストされていることを確かめてから,発展させてください.
- 税率も引数で渡せるようにする(食品の軽減税率 8 % も計算できるように)
- 税額だけを返す関数
get_tax(price)を足す - 1 円未満を切り捨てる(
int()またはmath.floor()) - 何個買うかを引数にして,合計金額を返す関数を足す
- ドーナツ屋さんにする.店内で食べる(
"eatin")か持ち帰る("takeout")かを文字で受け取って,税率を決めて返す関数get_rate(category)を足す
get_rate("たべる") のように,
どちらでもない文字が来たときにどうするかも決めておきましょう
(-1 を返す,など).
勝率(%)を返す関数 get_winning_rate(win, lose) と,
BMI を返す関数 get_bmi(height, weight) があります.
どちらも「数を受け取って数を返す」関数です.
テストされていることを確かめてから,発展させてください.
- 引き分けの数も引数に加えて,勝率を計算する
- 勝率から「絶好調」「まずまず」「立て直そう」を返す関数を足す
- BMI から標準体重(BMI 22 になる体重)を返す関数を足す
- 0 勝 0 敗のときに割り算でエラーにならないようにする
1 から n までを全部足した数を返す関数 get_sum(n) があります.
テストされていることを確かめてから,発展させてください.
aからbまでの総和を返す関数にする- 1 から n までの積(階乗)を返す関数
get_product(n)を足す - 偶数だけの総和・奇数だけの総和を返す関数を足す(第 7 章の剰余)
- ガウスの公式
n * (n + 1) / 2で計算する関数も作り,両方の答えが一致するかテストで確かめる
最小値と最大値の間のランダムな数を返す関数 make_random(low, high) と,
じゃんけんの勝敗を返す関数 janken_judge(hand1, hand2) があります.
手は 0=グー,1=チョキ,2=パーで表し,
結果は player1 から見て 1=勝ち・0=あいこ・
-1=負けを返します.
- 勝敗の数字ではなく「勝ち」「あいこ」「負け」の文字を返す関数を足す
- 手の数字から「グー」「チョキ」「パー」を返す関数を足す
- コンピュータとの対戦にして,キーボードから手を入力できるようにする
- 10 回勝負して,勝った回数を返す関数を足す
hand1 - hand2 の値で場合分けすると楽です.
差が 0 ならあいこ,-1 か 2 なら player1 の勝ち,
1 か -2 なら負けです.
random.randint(a, b) は a 以上 b 以下の
整数をランダムに返します.
コイン投げをまねる関数 flip() があります.
2 分の 1 の確率で True(表)を返します.
また simulate(n) は flip() を n 回呼び,
表が出た回数を返します.
- 試行回数を増やすと,表の割合が 0.5 に近づくことを確かめる(10 回・100 回・1000 回・10000 回で試す)
- 割合(%)を返す関数を足す
- サイコロ版
roll()を作り,1 の目が出る割合が 1/6 に近づくか確かめる - 表が何回連続で出たかを数える関数を足す
最後は自由制作です. 戻り値のある関数を 2 つ以上作り,それを使って絵を描いてください.
- 座標を返す関数(
return x, y) - 色を返す関数(
return "crimson") - 大きさ・角度・長さを計算して返す関数
- 「もう描いてよいか」を判定して返す関数(
return True)
math.sin を使って半径を波打たせると,花のような形になります.
まとめ
return 値で,関数から値を持ち帰らせる.その値を戻り値という.- 戻り値は,変数に入れる・そのまま
printする・計算に使う・別の関数の引数にする,のどれでも使える.受け取らなければ捨てられる. returnを実行すると,関数はそこで終わる.そのうしろの命令は実行されない.returnの無い関数はNoneを返している.- 返せる値の種類に制限は無い.数・文字・真偽値,
return a, bで 2 つ以上まとめて返すこともできる. - タートルでは,座標・距離・色を計算して返す関数が便利.面倒な計算を関数の中に隠せる.
mathモジュールにはsqrt・sin・cos・piなどがある.sin・cosに渡す角度はラジアンなので,math.radians()を忘れない.- 「人に聞く」「計算する」「見せる」を別々の関数にすると,計算する関数をテストできる.期待値を書いて PASS/FAIL を出すのが定石.
次の回では,データをまとめて持つリストを習います.
覚えておきたい数が 5 個でも 100 個でも,変数を 100 個作る必要はなくなります.
第 8 章で 1 匹ずつ名前をつけたかめも,リストに入れてしまえば
for で一斉に動かせます.
ここまでに作った関数と組み合わせると,書ける量が一気に増えます.