高階関数

高階関数

高階関数

 Python では「引数に関数を渡したり、戻り値として関数を受け取るような関数」を定義することもできます。このような関数のことを高階関数 (higher-order function) とよびます。いくつかのサンプルコードを書いてみたので、1 行ずつ丁寧に変数を追いながら高階関数の構造を理解するようにしてください。

関数を受け取って関数を実行する高階関数

 最初のサンプルコードは最も単純な高階関数です。

# https://python.atelierkobato.com/high/

# 高階関数g(y)の定義
def run_function(func):
    func()

def good_morning():
    print("おはよう!")

run_function(good_morning)
おはよう!

 run_function() は受け取った関数をそのまま実行するように定義されています。もちろん、実用上はこんなコードを書く必要性はありませんが、高階関数の仕組みを理解するために一度は動作を確認しておいてください。
 

値を受け取って関数を返す高階関数

 次は値を渡すと関数を返す高階関数を定義してみます。

# https://python.atelierkobato.com/high/

# 高階関数g(y)の定義
def g(k):
    def f(x):
        return x + k
    return f

# a =  x + 1
a = g(1)

# b = a(2) = 2 + 1
b = a(2)

print(b)
3

 高階関数 g(k) は引数に値を受け取って関数 f(x) を返します。
 ただし、渡した引数 k によって f(x) の形が変わります。

  g(0) ⇒ f(x) = x
  g(1) ⇒ f(x) = x + 1
  g(2) ⇒ f(x) = x + 2

 つまり g(k) は関数 x + k を生成する関数です。サンプルコードの変数 a には g(1) の戻り値、すなわち関数 x + 1 を格納しています。このように、Python では変数に関数オブジェクトを入れることができます。
 

関数を受け取って関数を返す高階関数

 次は数学の「合成関数」を高階関数で定義したコードです。

# https://python.atelierkobato.com/high/

# 合成関数 y = √f(x)
def sqr(func):
    def inner(x):
        return func(x)**0.5
    return inner

# mathモジュールのインポート
import math

# y = √logx
y = sqr(math.log)

# y(2) = √log(2)
print(y(2))
0.8325546111576977

 sqr()関数は受け取った関数の平方根をとるような関数 inner() を返してきます。上のコードにあるように、mathモジュールをインポートして、sqr() に math.log を渡すと、自然対数の平方根をとる関数を返します。次のようなコードでも同じ計算はできます:

import math

a = (math.log(2))**0.5

print(a)
0.8325546111576977

 しかしここで重要なことは、高階関数として定義された sqr() にはどんな関数でも渡すことのできる汎用性があるということです。合成関数は Python を使って数学や物理学の問題を解決しようとする場合に有用な手段となりえます。
 

関数と値を受け取って値を返す高階関数

# https://python.atelierkobato.com/high/

# mathモジュールをインポート
import math

# 関数と関数に渡す引数を受け取る関数
# hoはhigher-orderの略
def ho_func(func, x):
    return func(x)

# math.sqrt()に100を渡す
a = ho_func(math.sqrt, 100)

print(a)
10.0

 引数に「関数 func」と「関数 func が受け取る引数 x」を渡して「関数 func に引数 x を渡したときの戻り値」を返す関数を定義しています。ho_func() の引数に math.sqrt()関数と、math.sqrt()関数に渡す引数 100 を指定すると、math.sqrt(100) が戻ります。