はじめに
前回は、Python の文・インデント・変数・型・制御構文を扱いました。今回は、まとまった処理に名前を付け、必要なときに呼び出せる「関数」を見ていきます。
def で関数を定義する
関数は
def
で定義します。関数名と丸括弧の後ろにコロン
:
を付け、関数の処理をインデントして書きます。
| 1 2 3 4 5 | def add(a, b): return a + b result = add(1, 2) print(result) # 3 |
a
と
b
は、呼び出し元から値を受け取る引数です。
return
は値を呼び出し元へ返し、その時点で関数の実行を終えます。
return
を書かなかった場合や、値を指定せずに
return
した場合、戻り値は
None
になります。
関数は固有のローカルスコープを作ります。そのため、関数の中で代入した変数は、通常、その関数の中だけで利用するローカル変数になります。
| 1 2 3 4 5 6 | def make_message(name): message = f"こんにちは、{name}さん" return message print(make_message("田中")) print(message) # NameError |
最後の
message
は関数の外側から参照できないため、
NameError
になります。
引数の渡し方とデフォルト値
Python では、引数を位置で渡す方法と、名前を指定して渡す方法があります。名前を指定するものをキーワード引数と呼びます。
| 1 2 3 4 5 6 | def greet(name, suffix="さん"): return name + suffix print(greet("田中")) # 田中さん print(greet("田中", "様")) # 田中様 print(greet(name="田中", suffix="先生")) # 田中先生 |
suffix="さん"
は引数のデフォルト値です。呼び出すときに
suffix
を省略すると、この値が使われます。通常の引数を並べるときは、デフォルト値のない引数を、デフォルト値のある引数より前に置く必要があります。
/ と * で引数の渡し方を限定する
引数リストに
/
や
*
が現れることもあります。これらは実際に値を受け取る引数ではなく、引数の渡し方を区切る記号です。
| 1 2 3 4 5 | def greet(name, /, *, suffix="さん"): return name + suffix print(greet("田中")) # 田中さん print(greet("田中", suffix="様")) # 田中様 |
/
より前の
name
は「位置専用引数」なので、
greet(name="田中")
のように名前を指定して渡すことはできません。一方、
*
より後の
suffix
は「キーワード専用引数」なので、
greet("田中", "様")
のように位置で渡すことはできません。
/
と
*
の間にある引数は、位置とキーワードのどちらでも渡せます。
位置専用引数の
/
を Python で定義する関数に使えるようになったのは、Python 3.8 からです。キーワード専用引数を示す単独の
*
は、可変長引数の
*args
とは役割が異なります。
この記法を覚えると、公式ドキュメントにある次のような関数の表記も読めるようになります。
| 1 | sorted(iterable, /, *, key=None, reverse=False) |
iterable
は位置で渡し、
key
と
reverse
は指定するならキーワードで渡す、という意味です。
Python では関数も値として扱える
Python の関数は、数値や文字列と同じように、変数へ代入したり、他の関数の引数として渡したりできます。このように通常の値と同じように扱えるものを、第一級オブジェクトと呼びます。
| 1 2 3 4 5 6 7 8 9 10 11 | def shout(text): return text.upper() + "!" def whisper(text): return text.lower() + "..." def greet(name, style): print(style(name)) greet("Python", shout) # PYTHON! greet("Python", whisper) # python... |
greet()
の第 2 引数には、
shout
や
whisper
という関数そのものを渡しています。
shout
は関数を表す値であり、丸括弧を付けた
shout("Python")
はその関数の呼び出しです。
関数を引数として渡す書き方は、自作の関数だけでなく、組み込み関数でも使われます。
sorted()
は、要素を並べ替えた新しいリストを返す組み込み関数です。次の例では、そのまま呼ぶとアルファベット順に並びます。
| 1 2 3 4 | words = ["banana", "fig", "apple"] print(sorted(words)) # ['apple', 'banana', 'fig'] print(sorted(words, key=len)) # ['fig', 'apple', 'banana'] |
key
には、各要素から「並べ替えの基準になる値」を求める関数を渡します。ここで使った
len()
は、文字列を渡すと文字数を返す組み込み関数です。
key=len
と指定すると、
sorted()
はそれぞれの単語を
len
に渡し、返された文字数を基準に並べ替えます。この例では
6
、
3
、
5
を比較するため、短い単語から順に並びます。返されるリストの要素は、文字数ではなく元の単語のままです。
ここでも、
len()
と呼び出すのではなく、関数そのものを
len
と書いて渡しています。先ほど確認したシグネチャのとおり、
key
はキーワード引数として指定しています。
関数を呼び出せるのは def の実行後
Python はコードを上から順番に実行します。
def
も文の 1 つであり、その文が実行された時点で関数名が使えるようになります。そのため、次のコードは
add
がまだ定義されておらず、
NameError
になります。
| 1 2 3 4 | print(add(1, 2)) # NameError def add(a, b): return a + b |
ただし、「関数の呼び出しより前の行に、必ずその関数を書く必要がある」と覚えるのは正確ではありません。重要なのは、呼び出しが実際に実行される時点で、必要な
def
が実行済みかどうかです。
| 1 2 3 4 5 6 7 8 9 10 11 | def is_even(n): if n == 0: return True return is_odd(n - 1) def is_odd(n): if n == 0: return False return is_even(n - 1) print(is_even(10)) # True |
is_even()
の本体には、後ろで定義する
is_odd()
の呼び出しがあります。それでも動作するのは、
def is_even
を実行した時点では関数本体の処理は実行されないためです。最後の
is_even(10)
を呼び出す時点では、2 つの
def
がどちらも実行済みなので、互いを呼び出せます。
さいごに
今回は、
def
、引数、
return
という関数の基本から、位置専用引数とキーワード専用引数、関数そのものを値として渡す方法、そして定義と呼び出しのタイミングまでを扱いました。
特に、関数名に丸括弧を付けなければ関数そのものを渡せることと、呼び出す時点までに
def
が実行済みであればよいことを押さえておくと、Python のコードを読み解きやすくなります。
次回は list を扱います。要素の追加や取り出しだけでなく、文字列と共通する添字やスライス、
*
による繰り返しも見ていきます。