Python独学ノートの関数式プログラミング5——戻り関数

2504 ワード

関数を戻り値として使用
高次関数はパラメータとして関数を受け入れるほか,結果値として関数を返すこともできる.
可変パラメータの合計を実現するには、通常、関数は次のように定義されます.
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