関数から値を返すには「return文」を使用する。構文は次の通りだ。
return 戻り値
「戻り値」の部分には何らかの値(式)を記述する。変数でも構わないし、計算式でも構わない。ここでは簡単な例として「引数を取らず、常に整数値42を返す関数」を定義してみよう。
def get_ans4ultimateQ():
return 42
この関数は常に「42」を返すので、「return」の後にはそのまま「42」を置いているが、実際には何らかの計算や処理をした結果を返すのが一般的だ。また、return文によりその関数は実行を終了する。つまり、次のようなコードを書くことはできるが、最後の行は実行されない。
def get_ans4ultimateQ():
return 42 # 関数の実行はここで終了
print('can not reach this line') # この行は実行されることはない
return文によって、関数の実行が終了すると、プログラムの実行は「関数呼び出しの次」へと移動する。なお、値を返さない関数を定義しているのであれば、単に「return」とだけ書く。その場合は関数の実行がそこで終了して、その関数を呼び出した側で次のコードが実行される。上で見たhello関数ではreturn文がないが、これは関数本体に記述したコードの最後まで実行されたので、そこで関数の実行が終了して、呼び出し側にNoneが返されたということだ。
この関数を呼び出して、その戻り値を使用するコードは次のように書ける。
result = get_ans4ultimateQ()
print(result)
この場合、関数get_ans4ultimateQが呼び出されて、その実行が終わると、「42」という値が得られる。関数呼び出しの次には、「result = ……」という代入文が実行されるが、この右辺の値となるのが関数呼び出しで得られた値だ。結果、戻り値の「42」が変数resultに代入される。
そして、最後に次の行の「print(result)」が実行される。
実際の実行結果を以下に示す(以下の画像では、return文の後にprint関数呼び出しがあるバージョンを呼び出しているが、print関数による画面表示がないことにも注目しよう)。
一方、次のように書いてもよい。
print(get_ans4ultimateQ())
これは「関数get_ans4ultimateQの呼び出しをprint関数の引数」としている。この場合、関数get_ans4ultimateQを呼び出して得られた戻り値が、そのままprint関数に引き渡される。ただし、変数に値を代入していないので、この関数呼び出しの結果は「使い捨て」となって、後から利用することはできない。このような関数の使い方もあることは覚えておこう。
このコードを入力して関数を呼び出した結果を以下に示す。
上記の関数の名前は「get_ans4ultimateQ」となっている。このうち、「ans」は「answer」を、「4」は「for」を、「Q」は「Question」を意識して付けたものだ。つまり、この名前は「get_answer_for_ultimate_question」(究極の疑問の答えを求める)を短く表記したものだ*2。アンダースコア(_)は複数の単語を連ねたものを関数名とするときに、関数名を読みやすくするために入れたものだ(アンダースコアを入れずに、全ての単語を繋げていくと「getanswerforultimatequestion」となり一目では何を表しているかが分からなくなってしまう)。
関数名は、その関数が何をするものかを分かりやすく説明するものでなくてはならないので、このように長い名前になることがある。ただし、単に単語を連ねただけでは、読みづらい表記になってしまうので、必要に応じて、このようにアンダースコアを含めたり、短縮表記を用いたりすることがよくある。
*2 戻り値の「42」というのはDouglas Adams氏によるSF小説「銀河ヒッチハイク・ガイド」で「究極の疑問」に対する解答としてコンピュータが算出した値だ。Google検索でも「生命、宇宙、そして万物についての究極の疑問の答え」「生命、宇宙、全ての答え」などとして検索すると、この値が得られる。
なお、Pythonにおける「関数の命名規則」は「PEP 8 -- Style Guide for Python Code」と呼ばれるドキュメントで定められている。
関数名には英文字/アンダースコア/数字などを使えるが、「PEP 8」で推奨されているのは「英小文字のみで構成し、読みやすさを考慮して、適宜アンダースコアで単語をつなぐ」命名法だ(そういう意味ではこの関数の名前は微妙だが、「for」を意味する「4」や、「question」を省略した「Q」を使った方が分かりやすいと筆者は感じるが、以降はなるべくPEP 8に従った名前にしていく)。
次にもう少し複雑な処理をして、その結果を返す関数を定義してみよう。
本連載の第9回の「if〜elif〜else文」ではif文の説明の例として「FizzBuzz問題」を解くコードを取り上げた。そのコードは次のようなものだった*3。
*3 第2回「Hello Python」の「もう少し難しいHello Worldプログラム」で触れているように、「Try Jupyter」ページの「Jupyter Notebook」リンクから起動するPython環境では以下のコードがうまく動作しない。対処策としては上記ページにあるように、Binderを使う方法がある。以下では、Binderを使って起動した環境で話を続けることにしよう。
number = input('何か数値を入力してください: ')
number = int(number)
if number % 3 == 0 and number % 5 == 0:
print('FizzBuzz')
elif number % 3 == 0:
print('Fizz')
elif number % 5 == 0:
print('Buzz')
else:
print(number)
このコードは次のような条件を判定するものだ。
今度は、この判定を行う部分を「fizzbuzz」という名前の関数として定義してみよう。関数の仕様は次のようになる。
関数ボディーで実際に行う処理は既に見た通りなので、基本的にはこれを組み込めばよい。そうすると、fizzbuzz関数は次のようになる(パラメーターnumberをstr関数で文字列化するところだけ変更している*4)。
def fizzbuzz(number):
if number % 3 == 0 and number % 5 == 0:
print('FizzBuzz')
elif number % 3 == 0:
print('Fizz')
elif number % 5 == 0:
print('Buzz')
else:
print(str(number))
*4 パラメーターnumberの値を文字列化しているのは、その値が「3の倍数」「5の倍数」「3の倍数かつ5の倍数」のときには文字列を戻しているので、それらと合わせているからだ。時と場合によって、関数から文字列が返されたり、数値が返されたりすると、それを使用する側にしてみると使いづらい。そこで、ここでは関数が常に文字列を返すように調整しているということだ。
ただし、この関数はまだ値を返さずに、print関数で結果を表示するだけとなっている(正しく判定してその結果を画面に表示はしてくれるので、興味のある方は実行してみよう)。print関数を呼び出すのではなく、それぞれの値を返す必要がある。簡単なのは「print関数呼び出しをreturn文に置き換える」ことだ。すると、関数fizzbuzzは次のようになる。
def fizzbuzz(number):
if number % 3 == 0 and number % 5 == 0:
return 'FizzBuzz'
elif number % 3 == 0:
return 'Fizz'
elif number % 5 == 0:
return 'Buzz'
else:
return str(number)
この場合、if文の各節でreturn文を実行するので、その時点で関数の実行が終了することになる。一方、判定した結果を変数に保存しておいて、関数の最後でそれを返す方法もある。
def fizzbuzz(number):
result = str(number)
if number % 3 == 0 and number % 5 == 0:
result = 'FizzBuzz'
elif number % 3 == 0:
result = 'Fizz'
elif number % 5 == 0:
result = 'Buzz'
return result
こちらのコードでは、最初にパラメーターnumberに受け取った値を変数resultに保存しておき、「3の倍数なら変数resultに'Fizz'を代入」「5の倍数なら'Buzz'を代入」「3の倍数かつ5の倍数なら'FizzBuzz'を代入」し、最後に変数resultの値を返すようにしている。
前者のバージョンでは、if文の各節でそのまま関数の実行が終了するが、後者のバージョンではif文の各節が終了した後に関数末尾で実行されるreturn文で関数が終了する。後者の場合は、if文で得られた結果をさらに加工したり、別の処理を加えたりすることも可能だ。どちらの書き方が適切かは時と場合によるので、いろいろな書き方ができることを意識しよう。
実際にこれを呼び出すコードと組み合わせると次のようになる(ここでは最後のバージョンを使っているが、その前のものでも構わない)。
def fizzbuzz(number):
result = str(number)
if number % 3 == 0 and number % 5 == 0:
result = 'FizzBuzz'
elif number % 3 == 0:
result = 'Fizz'
elif number % 5 == 0:
result = 'Buzz'
return result
number = input('何か数値を入力してください: ')
number = int(number)
print(fizzbuzz(number))
これを実行した結果を以下に示す。
なお、ここでは関数定義(def文)が他のコードよりも先に書かれていることに注意しよう。「def文で関数を定義した後でなければ、その関数を利用することはできない」のだ。つまり、「関数は使う前に定義する」必要がある。
例えば、次のコードを考えてみよう。
print(some_func())
def some_func():
print('you called some_func')
some_func関数の定義とその呼び出しが前後している。これを実行してみるとどうなるだろう。
御覧の通り、エラーが発生した。エラーメッセージをよく見ると「some_funcという名前が定義されていない」とある。関数を定義することで、その名前が定義されるので、関数は使う前に定義することを忘れないようにしよう。
関数呼び出しの方法や、関数定義など、今回はPythonの関数の基本について見てきた。関数定義とは「自分が使えるさまざまなプログラム要素を組み合わせて、新たなプログラム要素を組み立てる」という作業である。ここでいう「プログラム要素」には、これまでに見てきた数値や文字列、変数や演算子、関数などのことだ。そして、作成した新たなプログラム要素である関数は、さらに別の関数を定義する際にも利用できる。このように、Pythonが標準で提供しているものを利用して、「できることを増やしていく」ことがプログラミングという作業だといえる。
次回以降では関数内部で使用する変数の有効範囲や関数呼び出し時の引数の渡し方、ラムダ式など、今回取り上げなかった関数についての少し高度な話題を取り上げる。
「Python入門」
Copyright© Digital Advantage Corp. All Rights Reserved.