Time Limit: 0 msec / Memory Limit: 0 KB
キーポイント
- 関数を定義するためには
def 関数名(パラメータ):
という記法を用いる - 関数の戻り値を返すには
return
文を用いる - 関数外の変数を更新するには
global
文を用いる
関数を自作する
前項では、今まで扱ってきた input
や len
が関数であったことや、これ以外にも色々な関数があることを学びました。この関数は予め用意されたものだけではなく、自分で動作を定めた関数を作成することも可能です。このように関数を作成することを、「関数を定義する」と呼びます。このように関数を定義するメリットの一つとして、複数の場所で行われる同じ処理をまとめることができるという点があります。
最も単純な関数定義
まず、最も単純な関数定義から見ていきます。以下は、1, 2, 3を 3 行で出力するという処理をする関数の定義です。
def print_numbers(): print(1) print(2) print(3)
def
は定義の英語であるdefine
から来ているキーワードで、関数の定義をすることを表します。それに続く部分(今回の場合はprint_numbers
)は関数の名前を表し、変数名と同様に自由な名前が使用できます。その後の ():
の部分は後ほど説明しますので、今は読み飛ばすこととします。
2 行目以降は、関数の処理を表す部分です。これは関数が呼ばれる度に処理されます。通常の Python のコードと同じように書くことができますが、インデントをする必要がある点には注意してください。
復習となりますが、関数は関数名の後にカッコをつけることで呼び出すことができます。この場合では、以下のようになります。
print_numbers() # 1, 2, 3が改行されて出力される
なお、関数は定義した後でないと呼び出すことができません。その点には注意してください。たとえば、以下のようなコードは実行時エラーとなります。
print_one() # NameError: name 'print_one' is not defined def print_one(): print(1)
引数を取る関数定義
次に、min(1, 2)
のように値を渡すことができる関数を定義してみます。以下は、第一引数と第二引数を足した数を出力する関数の定義と、その実行結果です。
def add_and_print(a, b): print(a + b) add_and_print(1, 2) # 3 が出力される
新しく出てきた事項として、一行目の(a, b)
という記述があります。これは、関数の後に書かれた一番目の要素(第一引数)をa
というパラメータに、二番目の要素(第二引数)をb
というパラメータに格納することを意味しています。このパラメータは関数の処理部分で変数のように用いることができます。
よって、この関数をadd_and_print(1, 2)
のようにして呼び出した場合、a
には1
、b
には2
が格納され、その状態でprint(a + b)
が実行された結果として3が出力されることになります。
戻り値を持つ関数定義
ここまでの文法では min
のような関数を実装することはできません。これは、return
文を用いることで、関数の中から呼び出し側に値を返すことができます。このような関数の「結果」を戻り値とよびます。以下は、return
分を用いた第一引数に 1 を足した値を返す関数の定義です。
def add_one(a): return a + 1
return
文の後には、関数の戻り値としたい値を記述します。すると、その値が関数呼び出しの式の値となります。よって、以下のように変数に代入したり、直接関数の引数として渡すことも可能です。
two = add_one(1) # 変数 two は 2 となる print(two) # 2 が出力される print(add_one(1) + 1) # 3 が出力される
また、return
文は実行された時点で関数の処理を終了するという役割もあります。これについては、後ほど詳述します。
まとめ
まとめると、関数の定義は以下のような文法で行うこととなります。
def 関数名(パラメータ): 処理
実は、関数のパラメータにはここでは説明しなかった文法がいくつか存在しています。これを用いると、print
関数のように引数の数を自由にできたり、sep=''
のように名前で指定できたりするパラメータを作成できるようになります。
興味のある方は、Python公式ドキュメント内の用語集 - parameterを参照してください。
関数定義時のテクニック
return 文の特性と複数の return 文を持つ関数
return
文は、同じ関数内の複数の箇所に書くことができます。例えば、以下はa
とb
の小さい方を戻り値とする関数の定義です。
def my_min(a, b): if a < b: return a else: return b
if
文がどのようなものだったかを思い出すと、a
がb
より小さいときにreturn a
が、そうでないときにreturn b
が実行されることになると分かります。
return
文は、実行された時点で関数の処理を終了します。つまり、以下のadd_one
関数のreturn a + 1
以降に書かれた文が実行されることはありません。
def add_one(a): return a + 1 print("ここには到達しない") return a + 2 # この行にも到達しない print("もちろんここにも到達しない")
これを用いると、my_min
を以下のように書き換えることができます。
def my_min(a, b): if a < b: return a # a < b のケースでは return a が実行されているため、ここには到達しない return b
このコードでは、return b
が実行されるのはa < b
でないときのみです。何故ならば、a < b
のときはreturn a
が実行されるので、そこで関数の処理が終了するためです。
また、値を返さない関数1でも、関数の処理を早期に終了する目的でreturn
文を使用することができます。
def print_a_is_7(a): if a == 7: print("a is 7") return # a == 7 のケースでは return が実行されているため、ここには到達しない print("a is not 7")
例えば、上の例では a == 7
のときには print("a is not 7")
が実行されません。これは、a == 7
のときは return
が実行されているので、そこで関数の処理が終了するためです。
関数内の変数
通常のプログラムと同様に、関数内でも変数を用いることができます。しかし、関数内で使用した変数は、基本的には関数の外部で使用することはできません。
以下の関数は、add_one
関数を変数を使って書き直したものです。
def add_one(a): result = a + 1 return result print(add_one(1)) # 2 が表示される print(result) # NameError: name 'result' is not defined
この関数自体は、想定している通りの動作をします。しかし、関数を呼び出した後にresult
変数を参照しようとしても、存在しない変数を使用しようとしたことを示すエラーが発生してしまいます。
変数を使用できる範囲のことをスコープと呼びます。今回の場合、result
変数のスコープはadd_one
関数内であるということになります。
一方で、関数の外の変数は自由に使用することが可能です。以下は、変数a
の値をプリントするprint_a
関数を用いた例です。
a = 0 def print_a(): print(a) print_a() # 0 が表示される a = 1 print_a() # 1 が表示される
変数a
は関数の外で宣言されていますが、その値をprint_a
関数の内部で用いることができていることが分かります。これは、変数a
のスコープがグローバル(つまり、コード全体)であるためです。このような変数のことをグローバル変数と呼びます2。
一方で、関数内でグローバル変数を変更する場合には注意が必要です。以下は、受け取った変数をa
に代入することを意図した関数update_a
を用いた例です。
a = 0 def update_a(val): a = val update_a(1) print(a) # 0 が出力される
この例から分かる通り、単に代入文を書くだけでは関数内ではグローバル変数の値を変更することができません3。グローバル変数に値を代入したい場合は、global
文を使用します。
a = 0 def update_a(val): global a a = val update_a(1) print(a) # きちんと 1 が出力される
関数内にてglobal 変数名
という形でglobal
文を使用すると、関数内で指定した変数を使用した際にグローバル変数として扱うようになります。また、複数の変数を指定したい場合は、global a, b, c
のようにカンマで区切ることで指定することができます。
global
文が必要な条件については一見複雑そうに見えますが、まとめれば「関数外部でも変数を使用していて、かつ関数内で代入をしている」場合となります。
よく混乱する例として、list
等を代入せずに変更するケースがあります。例えば、以下のようなケースではglobal
文は必要ありません。
li = [] def update_li(val): li.append(val) update_li(1) print(a) # [1] と出力される
これは、変数li
は変更されてはいるものの代入されていないためです。global
文が必要となるケースは、以下のように変数li
に代入しているケースです。
li = [] def update_li(val): global li li = li + [val] update_li(1) print(a) # [1] と出力される
nonlocal
ここからは、global
文についての補足となります。複雑なプログラムを書かない内は必要となることがないであろう知識なので、読み飛ばしても構いません。
for
文の中にfor
文を入れることができたのと同様に、Pythonでは関数内で関数を定義することが可能です。この際、以下のように関数内で用いたい外部の変数がグローバル変数でない場合が存在します。
def get_1(): value = 0 def set_1(): # ここで用いている value はグローバル変数ではないので、global は使えない value = 1 # Error: local variable 'value' referenced before assignment set_1() return value
このような場合に使用できる文として、nonlocal
文が存在します。これを用いて上のコードを書き直すと、以下の通りとなります。
def get_1(): value = 0 def set_1(): nonlocal value value = 1 set_1() return value
問題
リンク先の問題を解いてください。