Python独学ノートの関数式プログラミング5——戻り関数
2504 ワード
関数を戻り値として使用
高次関数はパラメータとして関数を受け入れるほか,結果値として関数を返すこともできる.
可変パラメータの合計を実現するには、通常、関数は次のように定義されます.
しかし、すぐに和を求める必要がなく、後のコードで必要に応じて再計算したらどうなりますか?和を求める結果ではなく、和を求める関数を返すことができます.
lazyを呼び出すとsum()の場合、返されるのは和を求める結果ではなく、和を求める関数です.
関数fを呼び出すと、加算の結果が本当に計算されます.
前述の例では、関数lazy_sumには関数sumも定義されており、内部関数sumは外部関数lazy_を参照することができる.sumのパラメータと局所変数、lazy_sumが関数sumを返すと,関連パラメータと変数が返される関数に保存され,この「クローズドパッケージ」と呼ばれるプログラム構造は大きな威力を持つ.
lazyを呼び出すとsumの場合、同じパラメータが入力されても、呼び出されるたびに新しい関数が返されます.
f 1()とf 2()の呼び出し結果は互いに影響しない.
クローズドパッケージ
上記の例では、返される関数が定義された内部でローカル変数argsを参照していることに気づきました.したがって、1つの関数が1つの関数を返すと、その内部のローカル変数が新しい関数に参照されるため、閉パッケージは簡単で、実現は容易ではありません.
もう1つの注意すべき問題は、返される関数がすぐに実行されるのではなく、f()が呼び出されるまで実行されないことである.例:
この例では、ループのたびに新しい関数が作成され、作成した3つの関数が返されます.
f 1(),f 2(),f 3()を呼び出すと、結果は1,4,9になると思いますが、実際の結果は:
全部9!なぜなら、返される関数は変数iを参照しているが、すぐに実行されるわけではないからである.3つの関数が返されると、参照される変数iは3になり、最終結果は9になります.
閉パッケージを返すときに覚えておくのは、戻り関数がループ変数を参照しないか、その後に変化する変数を参照しないことです.
必ず循環変数でどうすればいいですか?方法は、ループ変数の現在の値を、ループ変数がその後どのように変更されても、関数パラメータにバインドされる値が変わらないように、関数を再作成することです.
結果を見てみましょう.
欠点はコードが長く,lambda関数を用いてコードを短縮できることである.
Lambdaを試します:
高次関数はパラメータとして関数を受け入れるほか,結果値として関数を返すこともできる.
可変パラメータの合計を実現するには、通常、関数は次のように定義されます.
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
しかし、すぐに和を求める必要がなく、後のコードで必要に応じて再計算したらどうなりますか?和を求める結果ではなく、和を求める関数を返すことができます.
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
lazyを呼び出すとsum()の場合、返されるのは和を求める結果ではなく、和を求める関数です.
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>>f
<function lazy_sum.<locals>.sum at .....>
関数fを呼び出すと、加算の結果が本当に計算されます.
>>>f()
25
前述の例では、関数lazy_sumには関数sumも定義されており、内部関数sumは外部関数lazy_を参照することができる.sumのパラメータと局所変数、lazy_sumが関数sumを返すと,関連パラメータと変数が返される関数に保存され,この「クローズドパッケージ」と呼ばれるプログラム構造は大きな威力を持つ.
lazyを呼び出すとsumの場合、同じパラメータが入力されても、呼び出されるたびに新しい関数が返されます.
>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1 == f2
False
f 1()とf 2()の呼び出し結果は互いに影響しない.
クローズドパッケージ
上記の例では、返される関数が定義された内部でローカル変数argsを参照していることに気づきました.したがって、1つの関数が1つの関数を返すと、その内部のローカル変数が新しい関数に参照されるため、閉パッケージは簡単で、実現は容易ではありません.
もう1つの注意すべき問題は、返される関数がすぐに実行されるのではなく、f()が呼び出されるまで実行されないことである.例:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
この例では、ループのたびに新しい関数が作成され、作成した3つの関数が返されます.
f 1(),f 2(),f 3()を呼び出すと、結果は1,4,9になると思いますが、実際の結果は:
>>> f1()
9
>>>f2()
9
>>>f3()
9
全部9!なぜなら、返される関数は変数iを参照しているが、すぐに実行されるわけではないからである.3つの関数が返されると、参照される変数iは3になり、最終結果は9になります.
閉パッケージを返すときに覚えておくのは、戻り関数がループ変数を参照しないか、その後に変化する変数を参照しないことです.
必ず循環変数でどうすればいいですか?方法は、ループ変数の現在の値を、ループ変数がその後どのように変更されても、関数パラメータにバインドされる値が変わらないように、関数を再作成することです.
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i) , i f()
return fs
結果を見てみましょう.
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9
欠点はコードが長く,lambda関数を用いてコードを短縮できることである.
Lambdaを試します:
def count():
def f(j):
return lambda : j*j #
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i) , i f()
return fs