>>> import math
>>> def log(底): # エンクロージャ。関数「log底」を返す関数
... def log底(真数): # クロージャ。返される関数
... return math.log(真数, 底) # エンクロージャ内の変数「底」を、クロージャ内で利用する。
... return log底
...
>>> log(2)(8)
3.0
log(2)(8) == 3
の解説
1. log(2)
の呼び出し
まずlog(2)
が評価された時点で、エンクロージャlog(底)
が呼び出される。
1-1. def log底(真数): return math.log(真数, 2)
が実行される
エンクロージャ内で、クロージャの定義が実行される。この時、クロージャ内の変数はエンクロージャ内と共通であるため、
底==2
が成立する。
1-2. return log底
が実行される
エンクロージャ呼び出しlog(2)
の評価値は、math.log(真数, 2)
を返却する関数そのものである
2. log(2)(8)
の呼び出し
1-2節より、log(2)
は「math.log(真数, 2)
を返却する関数」として評価されるのだった。
故に、log(2)
は(lambda 真数: math.log(真数, 2))
と同じようなことをを意味するのだ。
log(2)(8)
つまり (lambda 真数: math.log(真数, 2))(8)
が呼び出されることで、真数=8
が代入され、
math.log(8, 2)
が実行されるのである。
演習. x
を受け取り、x
がmin
未満ならmin
、max
超ならmax
、どちらでもないならx
を返却する関数rerange(max,min)(x)
を作れ
1. def rerange(max,min):
まずは外側の関数(エンクロージャ)を定義します。
1-1. def rerange_max_min(x):
関数rerange
内に別の関数rerange_max_min
を作ります。rerange_max_min
が関数内関数、より具体的に言うとクロージャです。
1-1-1. y = max if x>max else (min if x<min else x)
今、rerange_max_min
内部にいます。①
rerange_max_min
はrerange
内部にあります。②
①②より、今rerange
内部にいます。
よって、引数max
とmin
が有効です。
1-1-2. return y
rerange_max_min
の戻り値を宣言しました。
この瞬間、rerange_max_min
は
x
を引数として受け取り、max if x>max else (min if x<min else x)
を返却する関数
となりました。
返却値max if x>max else (min if x<min else x)
をよく見てみましょう。
変数は、max
, x
, min
の3種類があります。
このうち、引数はx
だけです。それ以外の2種類は、「引数ではない『謎』の変数」です。
『謎』解きは1-2節で行います
1-2. return rerange_max_min
rerange
の戻り値を宣言しました。
この瞬間、rerange
は
min
,max
を引数として受け取り、
(
x
を引数として受け取り、max if x>max else (min if x<min else x)
を返却する関数
)
を返す関数となりました。
1-1節で「『謎』の変数」といったmin
, max
は、rerange_max_min
より外側の関数rerange
によって決まります。
故に、rerange_max_min
だけに注目している限り「謎」の変数です。もっと視野を広げ、rerange
全体まで見渡した今、謎が解けました。
>>> def rerange(max, min=0):
... def rerange_max_min(x):
... y = max if x>max else (min if x<min else x)
... return y
... return rerange_max_min
...
>>> [rerange(4,2)(成分) for 成分 in range(6)]
[2, 2, 2, 3, 4, 4]
>>> [rerange(4)(成分) for 成分 in range(6)]
[0, 1, 2, 3, 4, 4]
>>>