関数

Python で関数オブジェクトを定義する際に def コマンドを利用する。平均や分散などを計算する際に、NumPy や SciPy で用意されたメソッドを利用すればよいが、独自のアルゴリズムで計算したい場合などは、関数を一からつくり上げる必要がある。

基本的な作り方

関数は、def に続いて関数名とコロンを書き、その次の行をインデントし、関数の処理を書く。例えば、2 つの引数(xy)を受け取り、その差を返す関数は次のように作成する。ただし、関数は diff とする。

def diff(x, y):
    sa = x - y
    return sa

自作した関数 diff は以下のように利用する。

diff(30, 10)
## 20

dis(y = 10, x = 30)   
## 20

関数を利用するにあたって、引数が足りないときにエラーが発生する。例えば、diff 関数の場合、2 つ目の引数 y を省略すると、以下のようなエラーが発生する。

diff(30)
## Traceback (most recent call last):
##   File "<stdin>", line 1, in <module>
## TypeError: diff() missing 1 required positional argument: 'y'

関数の引数に初期値を設定する方法

関数の引数に初期値を設定することができる。初期値が設定された関数が呼び出されると、引数が与えられていないは初期値を利用するようになる。例えば、次の関数では 、引数 x が与えられていない場合は x = 30 として初期化を行い、引数 y が与えられていない場合は y = 0 として初期化を行う。

def diff(x = 30, y = 0):
    sa = x - y
    return sa

diff(20)
## 20

diff()
## 30

複数個の値を返す方法

関数は 1 つの値をしか返せない。複数の値を返す必要がある場合、リストあるいはディクショナリにして返す。

def plus_and_minus(x, y):
    a = x + y
    b = x - y
    c = [a, b]
    return c

z = plus_and_minus(20, 10)
print(z)
## [30, 10]

また、次のように書くと、タプルとして返すようになる。

def plus_and_minus(x, y):
    a = x + y
    b = x - y
    return a, b

z = plus_and_minus(20, 10)
print(z)
## (30, 10)

再帰処理

関数の中で、自分自身を呼び出すことを再帰呼び出しとよぶ。このような再帰的な処理を行う関数を再帰関数という。数学上、漸化式で表される問題を再帰関数で解くことができる。フィボナッチ数列がその代表例である。フィボナッチ数列は、0, 1, 1, 2, 3, 5, 8, ... のように、n 番目の値 f(n) は、n - 1 および n - 2 のときの値の和 f(n-1) + f(n-2) として表せる。

\[ f(n) = f(n-1) + f(n-2) \]

n 番目のフィボナッチ数を求めるには、n - 1 と n - 2 番目の値がわかれば良いので、プログラムは、下のように書ける。

def fibo(n):
  
    if n == 0 or n == 1:
        s = n;
    
    else:
        s = fibo(n - 1) + fibo(n - 2)
  
    return s

fibo(9)
## 34

参照渡し

Python は、関数にオブジェクトを代入するときに、基本的に参照渡しである。関数内部で、代入されたオブジェクトの値を書き換えると、その参照元のオブジェクトの値も書き換えられるため、十分に注意すること。ただし、整数や文字列などが代入されている immutable オブジェクトの場合は、関数内部でコピーが作られるので、値渡しとみなせる。

def add_M(x):
    x.append('M')
    return x

def add_N(x):
    y = x
    y.append('N')
    return y


a = ['A', 'B', 'C']

print(a)
## ['A', 'B', 'C']

add_M(a)
print(a)
## ['A', 'B', 'C', 'M']

add_N(a)
print(a)
## ['A', 'B', 'C', 'M', 'N']

値渡し

関数の引数として渡されたオブジェクトが関数内で変更されても、その関数を抜けた時にその変更されないようなことにしたい場合、値渡しをする。ただし、Python では参照渡しが基本で、値渡しができない。そのため、関数の内部で、オブジェクトを受け取った後に、そのオブジェクトのコピーをとるなどの操作を行い、見かけ上の値渡しを行う必要がある。

import copy

def add_M(x):
    y = copy.deepcopy(x)
    y.append('M')
    return y

def add_N(x):
    y = copy.deepcopy(x)
    z = y
    z.append('N')
    return z


a = ['A', 'B', 'C']

print(a)
## ['A', 'B', 'C']

b = add_M(a)
print(a)
## ['A', 'B', 'C']
print(b)
## ['A', 'B', 'C', 'M']

b = add_N(a)
print(a)
## ['A', 'B', 'C']
print(b)
##['A', 'B', 'C', 'N']