Python学習ノートの関数を戻り値、閉パッケージとして解釈する
5072 ワード
関数を戻り値として使用
高次関数はパラメータとして関数を受け入れるほか,結果値として関数を返すこともできる.
可変パラメータの和を実現する.通常、和を求める関数は次のように定義されます.
しかし、すぐに和を求める必要がなく、後のコードで必要に応じて再計算したらどうなりますか?和を求める結果ではなく、和を求める関数を返すことができます!
lazyを呼び出すとsum()の場合、返されるのは和を求める結果ではなく、和を求める関数です.
関数fを呼び出すと、加算の結果が本当に計算されます.
この例では関数lazy_sumには関数sumも定義されており、内部関数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になります.
閉パッケージを返すときに覚えておくのは、戻り関数がループ変数を参照しないか、その後に変化する変数を参照しないことです.
ループ変数を参照する必要がある場合はどうしますか?方法は、ループ変数の現在の値をバインドする関数をもう1つ作成します.ループ変数がその後どのように変更されても、関数パラメータにバインドされた値は変わりません.
欠点はコードが長く,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 sum at 0x10452f668>
関数fを呼び出すと、加算の結果が本当に計算されます.
>>> f()
25
この例では関数lazy_sumには関数sumも定義されており、内部関数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になります.
閉パッケージを返すときに覚えておくのは、戻り関数がループ変数を参照しないか、その後に変化する変数を参照しないことです.
ループ変数を参照する必要がある場合はどうしますか?方法は、ループ変数の現在の値をバインドする関数をもう1つ作成します.ループ変数がその後どのように変更されても、関数パラメータにバインドされた値は変わりません.
>>> def count():
... fs = []
... for i in range(1, 4):
... def f(j):
... def g():
... return j*j
... return g
... fs.append(f(i))
... return fs
...
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9
欠点はコードが長く,lambda関数を用いてコードを短縮できることである.