関数入門

どのプログラミング言語でも重要な原則の一つに「重複を避けよ」があります。何度も発生する動作があれば,それを一度定義すればそのコードを動作を行う必要のあるところで呼び出すことができます。

すでにコードを重複していますので,そろそろ簡単な関数を使ってみましょう。関数はプログラマにとって仕事を減らすもので,関数を上手に使えばミスをしにくくなります。

関数とは?

関数は動作を集めて,名前をつけたものです。これまでPython言語に組み込まれている関数 string.title()list.sort()などを多数使ってきました。自分で関数を定義して,Pythonに新たなふるまいを"教える"ことができるようになります。

一般的な文法

一般的な関数は次のような形をしています。

# Let's define a function.
def function_name(argument_1, argument_2):
	# Do whatever we want this function to do,
	#  using argument_1 and argument_2

# Use function_name to call the function.
function_name(value_1, value_2)

このコードは動きませんが,どのように関数が使われるか一般的に示しています。

  • 関数を定義する
    • キーワードdefで始め,Pythonに関数のdefine(定義)を始めることを伝えます。
    • 次に関数に名前をつけます。変数名はどんな種類の値を変数が含んでいるかを示し,関数名は関数が何をするかを示すべきです。
    • 関数の動作に必要な値それぞれに名前をつけます。
      • 基本的には変数名ですが,関数内でのみ使われます。
      • プログラムの他の部分と異なる名前をつけても構いません。
      • 関数の引数と呼ばれています。
    • 関数を定義する行は最後に必ずコロンをつけます。
    • 関数の中には,関数がする仕事に必要なコードを書きます。
  • 関数を使う
    • 関数を呼ぶには,関数名の後に丸括弧を書きます。
    • 括弧の中には関数で使う値を与えます。
      • current_namecurrent_ageのような変数でも,'eric'や5のような実際の値でも構いません。

基本的な例

単純な最初の例として,人にお礼を述べるプログラムを示します。この例を見てコードを理解してみましょう。まず,このプログラムの最初の版は,これまでに書いてきたような関数を使わないものです。

print("You are doing good work, Adriana!")
print("Thank you very much for your efforts on this project.")

print("\nYou are doing good work, Billy!")
print("Thank you very much for your efforts on this project.")

print("\nYou are doing good work, Caroline!")
print("Thank you very much for your efforts on this project.")
You are doing good work, Adriana!
Thank you very much for your efforts on this project.

You are doing good work, Billy!
Thank you very much for your efforts on this project.

You are doing good work, Caroline!
Thank you very much for your efforts on this project.

関数は繰り返されるコードを一つにまとめて,使いたいときに呼びたします。同じプログラムを関数を使って書くとこのようになります。

def thank_you(name):
    # This function prints a two-line personalized thank you message.
    print("\nYou are doing good work, %s!" % name)
    print("Thank you very much for your efforts on this project.")
    
thank_you('Adriana')
thank_you('Billy')
thank_you('Caroline')
You are doing good work, Adriana!
Thank you very much for your efforts on this project.

You are doing good work, Billy!
Thank you very much for your efforts on this project.

You are doing good work, Caroline!
Thank you very much for your efforts on this project.

元のコードでは,print文の組は3回実行されましたが,唯一の差は感謝される人の名前でした。このような繰り返しを見たら,関数を定義してプログラムを簡潔にできます。

キーワードdefはPythonに関数を定義することを伝えています。関数に名前をつけます。ここではthank\_you()としました。変数の名前はどのような情報が格納されているか関数の名前は関数が何をするかを示すようにすべきです。次に丸括弧を置きます。その間に関数が仕事をするために必要とする変数に名前をつけて並べます。この例では関数は,感謝のメッセージに使う名前が必要です。変数nameにその値が格納され関数thank\_you()に渡されます。

関数を使うには,関数の名前の後に関数が仕事をするために必要とする値を与えます。この例では関数を3回呼んで,それぞれ異なる名前を渡しています。

よくある間違い

関数は,プログラム中で使う前に定義します。例えば,関数をプログラムの最後に置くとうまく動作しません。

thank_you('Adriana')
thank_you('Billy')
thank_you('Caroline')

def thank_you(name):
    # This function prints a two-line personalized thank you message.
    print("\nYou are doing good work, %s!" % name)
    print("Thank you very much for your efforts on this project.")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-a1b6b8373f44> in <module>()
----> 1 thank_you('Adriana')
      2 thank_you('Billy')
      3 thank_you('Caroline')
      4 
      5 def thank_you(name):

NameError: name 'thank_you' is not defined

最初の行でPythonにthank_you()を走らせるように求めていますが,Pythonはまだこの関数をどうしたら良いのか知りません。関数をプログラムの最初に定義すれば,必要なときに使うことができます。

二つ目の例

リストをソートする二つの異なる方法を紹介しました。コードには繰り返しが多いものでした。2行要してforループを使ってリストを印字していますが,この2行を繰り返しがリストの中身を印字しようとする度に必要です。これは関数を使うのにぴったりの例なので,関数を使うとコードがどのようになるか見てみましょう。

まず関数を使わないとコードは次のようになります。

students = ['bernice', 'aaron', 'cody']

# Put students in alphabetical order.
students.sort()

# Display the list in its current order.
print("Our students are currently in alphabetical order.")
for student in students:
    print(student.title())

# Put students in reverse alphabetical order.
students.sort(reverse=True)

# Display the list in its current order.
print("\nOur students are now in reverse alphabetical order.")
for student in students:
    print(student.title())
Our students are currently in alphabetical order.
Aaron
Bernice
Cody

Our students are now in reverse alphabetical order.
Cody
Bernice
Aaron

同じことをするコードは,リストを印字する関数を使うと次のようになります。

def show_students(students, message):
# Print out a message, and then the list of students
print(message)
for student in students:
print(student.title())
students = ['bernice', 'aaron', 'cody'] # Put students in alphabetical order. students.sort()
show_students(students, "Our students are currently in alphabetical order.")
#Put students in reverse alphabetical order. students.sort(reverse=True)
show_students(students, "\nOur students are now in reverse alphabetical order.")
Our students are currently in alphabetical order.
Aaron
Bernice
Cody

Our students are now in reverse alphabetical order.
Cody
Bernice
Aaron

関数を使うと,ずっときれいになりました。必要な動作は,リスト内の学生をメッセージとともに示すことです。この動作にshow_students()という名前をつけました。

この関数は二つの情報を受け取って仕事をします。学生りリストと表示するメッセージです。関数の中では,メッセージを印字しリストをたどるコードは,関数を使わないコードと全く同じです。

プログラムの残りの部分がきれいなったのは,リストを変えることに着目したコードで,リストを印字するコードを置き換えたからです。リストを定義し,それをソートして関数を読んでリストを印字します。リストをもう一度ソートし,異なるメッセージとともに印字する関数を再び呼びます。この方が読みやすいコードです。

関数を使う利点

以上の例から関数を使ういくつか利点が分かります。

  • 一連の指示を書くのは一度です。上に示した簡単な例でもいくらか仕事を節約していますが,もっと大きなプログラムではさらに節約できます。
  • 関数が動作すれば,そのコードについて心配する必要は無くなります。プログラム中でコードを繰り返す度,間違いを犯す可能性があります。関数を書くということは誤りを直すのが1箇所になルため,バグを修正すれば関数が正しく動き続けることに確信が持てます。
  • 関数のふるまいを変更すれば,関数が呼ばれればいつも変更がいつも反映されます。新しいふるまいが必要になったときに,プログラム中の多数の場所でコードを変更するよりかなりましです。

ちょっとした例として,印字の見栄えをよくするために中黒をつけた一覧の形にすると決めたとします。関数を使わない場合,いちいちprint文を変更しなくてはなりません。関数を使えば,関数内のprint文を変更するだけで済みます。

def show_students(students, message):
    # Print out a message, and then the list of students
    print(message)
    for student in students:
        print("- " + student.title())

students = ['bernice', 'aaron', 'cody']

# Put students in alphabetical order.
students.sort()
show_students(students, "Our students are currently in alphabetical order.")

#Put students in reverse alphabetical order.
students.sort(reverse=True)
show_students(students, "\nOur students are now in reverse alphabetical order.")
Our students are currently in alphabetical order.
- Aaron
- Bernice
- Cody

Our students are now in reverse alphabetical order.
- Cody
- Bernice
- Aaron

関数はPythonに新しいふるまいを教える方法であると考えることができます。以上例では,Pythonに学生一覧をハイフンを使って作る方法を教えました。今後はいつでもPythonに学生の名前に対してこの動作を実行させることができます。

値を返す

作成した関数は全て値を返すことができます。これは関数がする一番の仕事ともおまけとも考えられます。次の関数は数値を取り,数値に対応する単語を返します。

def get_number_word(number):
    # Takes in a numerical value, and returns
    #  the word corresponding to that number.
    if number == 1:
        return 'one'
    elif number == 2:
        return 'two'
    elif number == 3:
        return 'three'
    # ...
    
# Let's try out our function.
for current_number in range(0,4):
    number_word = get_number_word(current_number)
    print(current_number, number_word)
0 None
1 one
2 two
3 three

思ったように動作しないプログラムを見て,このようなプログラムがどのように改善されうるか理解するのもときにはためになります。上の例では,Pythonのエラーはなく全てのコードはPythonの文法として適切です。論理的なエラーか出力の最初の行にあります。

関数に送る範囲に0を含めないか,知らない値を受けたとき関数がNone以外を返すようにする必要があります。関数に単語'zero'を教えることにします。それだけでなく,else節を追加して一連のifにない数値に対してはより情報量の多いメッセージを返すようにします。

def get_number_word(number):
    # Takes in a numerical value, and returns
    #  the word corresponding to that number.
    if number == 0:
        return 'zero'
    elif number == 1:
        return 'one'
    elif number == 2:
        return 'two'
    elif number == 3:
        return 'three'
else:
return "I'm sorry, I don't know that number."
# Let's try out our function.
for current_number in range(0,6):
number_word = get_number_word(current_number) print(current_number, number_word)
0 zero
1 one
2 two
3 three
4 I'm sorry, I don't know that number.
5 I'm sorry, I don't know that number.

関数でreturn文を使うときに注意すべきことは,return文に到達した時点で関数の実行が停止することです。例えば,関数が値を返した後に行を追加してもget_number_word()関数に実行されることはありません。

def get_number_word(number):
    # Takes in a numerical value, and returns
    #  the word corresponding to that number.
    if number == 0:
        return 'zero'
    elif number == 1:
        return 'one'
    elif number == 2:
        return 'two'
    elif number == 3:
        return 'three'
    else:
        return "I'm sorry, I don't know that number."
    
# This line will never execute, because the function has already
# returned a value and stopped executing.
print("This message will never be printed.")
# Let's try out our function. for current_number in range(0,6): number_word = get_number_word(current_number) print(current_number, number_word)
0 zero
1 one
2 two
3 three
4 I'm sorry, I don't know that number.
5 I'm sorry, I don't know that number.

詳しくは後で

関数に関して学ぶことはもっとありますが,詳しくは後回しにします。ここでは,プログラム中に何度も同じコードを見つけたら,どんどん関数を使ってください。今後関数を取り上げるときに学ぶことを少し紹介します。

  • 関数の引数に既定値を与える方法
  • 関数が異なる数の引数を許容するようにする方法ー

練習問題

挨拶

  • 人の名前を取り,挨拶を印字する関数を書いてください。
    • 挨拶は最低3行以上で,それぞれの行に人の名前を含めましょう。
  • 関数を使って少なくとも3名の異なる人に挨拶してください。
  • ボーナス: 3名をリストに可能し,forループから関数を呼んではどうでしょうか。

フルネーム

  • ファーストネーム(名)とラストネーム(姓)を取り,きれいに整形したフルネームを文で印字してください。文は簡単に"Hello full_name"で構いません。
  • 関数を3回呼んでください。毎回異なる名前を使いましょう。

足し算計算機

  • 二つの数値を取り,それらを足す関数を書いてください。関数は二つの数値と結果を示す文を印字するようにしてください。
  • 異なる3つの数値の組を使って関数を呼んでください。

値を返す計算機

  • 足し算を修正して関数が二つの数値の話を返すようにしてください。印字は関数の外に出します。

List Exercises - Functions

発展問題

歌詞

  • 多くの歌は,馴染み深い順序でバーズ, リフレーン, バーズ, リフレーンとなっています。 バーズは物語を伝える部分で繰り返されません。リフレーンは,その歌を通じて繰り返される部分です。
  • song you likeの歌詞のうち,このパターンに従っているところを探してください。この歌の歌詞を印字するプログラムを書いてください。Python コードはなるべく短くしてください。ヒント

ヒント

ヒントは一番下にあるので,ヒントを見ないで練習問題を解くこともできるようにしてあります。

歌詞

  • リフレーンの歌詞を印字する関数を書いてください。この関数を歌の中でリフレーンが登場する度に使ってください