プログラミングにおいて関数は、ある特定の機能を持たせたコードを再利用するのに重要な方法である。

一つのプログラムにおいて、何度も同じようなコードを使い回し、冗長的なコードになっているようであれば、それは関数に代替する価値がある。

コードが冗長的になると、重複した処理内で少しでもコードを改変する必要に迫られた時、全ての箇所を洗い出し修正を行わなければならない。
また、何よりコードが長くなり非常に管理しづらくなる。

例として消費税の計算を見てみよう。

# 関数を使わず税込の合計金額を算出する例
x1 = 100
y1 = 300
z1 = 250
sum = (x1 + y1 + z1) * 1.08

x2 = 150
y2 = 80
z2 = 450
sum = (x2 + y2 + z2) * 1.08

関数を使わないと、例えば消費税が10%に上がった場合、1.08の値を全て洗い出し1.1に変更しなくてはならない。
数が少なければまだマシだが、このようなプログラムは危険極まりないコードだ。

次に関数を使用した例を見てみよう。

pythonの関数はdefキーワードによって作成する。

# 関数を使った例
def func_tax(x, y, z):
    TAX = 1.08
    return (x + y + z) * TAX

x1 = 100
y1 = 300
z1 = 250
sum = func_tax(x1, y1, z1)

x2 = 150
y2 = 80
z2 = 450
sum = func_tax(x2, y2, z2)

これなら税率が変わった時、func_tax関数のTAXの値を書き換えるだけで、全ての計算に変更が適用されることになる。

引数には位置引数とキーワード引数がある

関数は引数を取ることができ、引数を利用して関数内で様々な計算をおこなうことができる。

位置引数

関数が通常とる引数のことで()の中に任意の引数名を指定する。

def func_sub(x, y):
    return x - y

x = 1
y = 2
z1 = func_sub(x, y) # -1
z2 = func_sub(y, x) # 1

関数呼び出しの際に引数を入れるわけだが、呼び出しの時に入れた順番のとおりに関数は引数を取る。
つまり、z1ではx, yの順番で引数を指定したので、関数内では「1 – 2」の計算が行われ結果-1が返り、z2では引数を逆順で指定したため「2 – 1」の計算が行われ1が返ることになるのだ。

キーワード引数

キーワード引数は、主にデフォルト値やオプション値を取り扱う時に使われる。

関数定義の際に、任意のキーワードとデフォルト値をセットしておく。

def func_sum(x, y, tax=1.08):
    return (x + y) * tax

x = 100
y = 200
z = func_sum(x, y) # 324.0
z = func_sum(x, y, tax=1.1) # 330.0

func_sum関数の呼び出しの際、第3引数を省略するとデフォルト値の1.08がtaxに代入され、呼び出しの際に第3引数に値をセットするとtaxが指定の値に更新される。

ちなみに7行目のtaxは省略し「1.1」のみの記述でもOKだ。

引数のルール

キーワード引数はコードの可読性が上がるものだが、とある制約が設けられている。

関数の中に位置引数とキーワード引数が混在する場合、必ず位置引数の後ろにキーワード引数を定義する必要があるということだ。

def func_sum(x, y, tax=1.08, a):
    return (x + y) * tax

つまり、このような定義の仕方だとエラーになってしまうのだ。

関数からアクセスする変数のスコープについて

変数のスコープにはグローバルスコープローカルスコープがある。

まずは関数内で定義したaという変数を見ていこう。

def func():
    a = []
    for i in range(5):
        a.append(i)

この関数を呼び出すと、aという配列に0〜4までの値が代入される。
ただし、この関数内で定義したaは関数が終了すると同時に破棄されるので、関数の外でaを呼び出すとエラーが発生する。

次に関数の外で変数を定義した例を見てみる。

a = []

def func():
    global a
    for i in range(5):
        a.append(i)
        
func()
print(a) # [0, 1, 2, 3, 4]

関数の外で定義した変数に値を代入する場合は、明示的にglobalキーワードを関数内で使うことで、グローバル変数を扱うことができるようになる。

しかしプログラミングでは、あまりこういった書き方はすすめられないようで、もしglobalキーワードを多用したいのであれば、クラスを使ったオブジェクト指向プログラミングをする方が良いと言われている。

複数の戻り値を返す

returnキーワードで、関数内で処理した結果の値を戻り値として返すことができるが、pythonでは簡単な方法で複数の値を返すことができる。

def func():
    a = 1
    b = 2
    return (a + b), (a - b), (a * b)

x, y, z = func()

x # 3
y # -1
z # 2

実はよく見るとこの方法は、returnキーワードでタプルを返しているのだ。
x, y, zはタプルを展開した各値を変数に代入しているということで、関数funcは一つのオブジェクト(タプル)を返しているだけだということが分かる。

また、察しの良い方ならすでに気づいているとは思うが、ディクショナリを返すこともできるのだ。

def func():
    a = 1
    b = 2
    return {'a': a, 'b': b}

d = func()

d['a'] # 1
d['b'] # 2

まとめ

プログラミングにおいて関数は大変便利なものだ。

プログラミング初心者は皆コードが冗長的になりやすいが、注意深くコードを観察し、冗長コードを関数化するだけでもプログラミング能力はだいぶ上達するだろう。