Python入門(7) 関数を定義する

ソースコード(とくに、他人が書いた)を追うことでプログラム処理の流れを理解することは容易いことではない。 記述が長くなるほど理解は困難になり、そもそもそのプログラムが正しい結果をもたらすかどうかも分からなくなる。

次のスクリプトを一瞬に理解できるだろうか。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
a = [6, 9, 12, 4, 5, 8]
b = [21, 93, 11, 54]
sky = 1000000000
for blue in a:
    if blue < sky:
       sky = blue
print sky

sea = 1000000000
for fish in b:
    if fish < sea:
        sea = fish
print sea

ここには2つの課題が潜んでいる。

変数名の命名法については、プログラマのセンスに委ねられているわけだが、変数などがになっている意味を明らかにするように工夫すると俄然ソースコードは読み易くなる。 おなじことは、ソースコードファイル名についても当てはまる。 上と同じスクリプトであるが、次のスクリプトは分かりやすくなっているはずだ(変数 minimum を maximum とした命名は最悪だよね)。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

a = [6, 9, 12, 4, 5, 8]
b = [21, 93, 11, 54]
minimum1 = 1000000000
for item in a:
    if item < minimum1:
       minimum1 = item
print minimum1

minimum2 = 1000000000
for item in b:
    if item < minimum2:
       minimum2 = item
print minimum2
演習: このスクリプトは何をしているかを説明し、実行してみなさい。

プログラムには、ソースコードの役割を明確化し、同じような処理をするときには再利用(そうすべきだ!)するための言語上の特徴を備えている。 それが関数(function)定義である。 次のように、上のスクリプトを関数を使って書き換えてみよう。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def minimum(numlist):
    mini = 1000000
    for i in numlist:
       if i < mini:
           mini  = i
    return mini

a = [6, 9, 12, 4, 5, 8]
b = [21, 93, 11, 54]
print minimum(a)
print minimum(b)

上の例では、予約語 def に続いて関数 minimum を4行目から9行目で定義している。 さらに、return を使って関数の返す値(戻り値)を指定している。 returnは関数内でのみ利用できる(returnが関数内で常に必要というわけではない)。

関数定義において、関数名に続く括弧( )内に現れるものを仮引数(formal parameter)といい、13, 14行で関数に渡される a や bを実引数(actual parameter/argument)という。

このスクリプトは、関数関数 minimum を使うと、実質的には11行から14行だけで済むことことがわかる。 関数を使うことで処理手順を再利用し、処理の流れが明確になったことに注目しよう。

演習: 上の関数定義には、実用上の問題がある。指摘してみなさい。

関数の定義

Pythonの関数は次の形式で定義する。 引数を必要としない関数でも括弧 ( ) は省略できない。 関数定義のための予約語 def の行末にはコロン(:)があることに注意。

def 関数名(仮引数の並び):
    関数本体の記述

関数の本体の記述は、かならず空白文字1文字以上の字下げ(インデント)が必要である(Pythonの場合、字下げは本質的書式である)。

ひとたび関数を定義しておくと、関数を定義した後の行でその関数を呼び出して使うことができる(関数呼び出し(function call))。 ただし、Pythonでは関数呼び出しの実行時には、その行以前に関数が定義されていなければならない(前方参照の禁止再帰関数の前方参照も参照)。 次のスクリプトは実行できない。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

a = 4
b = 5
print summation(a, b)

def summation(x, y):
    return x + y

これを実行させると次のエラーが返る。 最後の行にあるように、上のスクリプトで関数呼び出しした6行目で、summationが見つからないというエラーが生じた。 summationを見つけるには7行目から先の前方参照が必要であるが、Pythonのような動的言語では、前方参照は許されていない。 上のスクリプトで、6行目を関数定義した9行目以降に移動してやれば、正しく a と b の和が出力される。

$ ./forward_refer.py
Traceback (most recent call last):
  File "./forward_refer.py", line 7, in <module>
    print summation(a, b)
NameError: name 'summation' is not defined
演習: 関数の前方参照に失敗して、同様なエラーメッセージが表示されることを確かめなさい。

関数定義では明示的に関数値を返す return が常に必要ではない。 次のスクリプト func_hello3.py で定義された関数 hello3 は引数をとらずに(それでも実行時には8行目にあるように括弧( )は必要)、値も返さない (厳密に言うと、関数値 None を返している)。 func_hello3.py の実質は関数呼び出しする8行目1行だけである。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def hello3():
    for i in range(3):
        print "Hello, world"

hello3()
演習: スクリプト func_hello3.py を実行してみなさい。