入れ子の関数(Python)
Google Python Style Guide の和訳をお昼休みにすこしずつ進めている。
今日は 2.6 節の入れ子のクラスと関数を訳していた。
ところでこの節、のっけに以下の記述がある。
fine when used to close over a local variable
close をどう訳すかという点で悩む。たぶん「ローカル変数を(クロージャ―として)閉じこむのはよい」だろうと考えている。
しかし Python のクロージャーはなかなかクセが強い。 global や nonlocal で明示的に指定しないかぎり、外のスコープの変数は「読める」けれど「更新できない」。(2.6.1 にも以下の注記がされているくらい)
Nested functions have read-only access to variables defined in enclosing scopes.
読み取り専用と考えると、クロージャーとしての使いどころはなんだろうか。(そして書きかえられるしても、クロージャーはどう使ったら「よい」と感じられるだろう?)
* * *
クロージャーと聞いて、まず浮かぶのはカウンターをつくる例。
def mk_counter(starts_with: int = 0):
def incr():
nonlocal starts_with
t = starts_with
starts_with += 1
return t
return incr
指定した数で数えはじめるカウンター「関数」をつくって返す「高階関数」。
こんな感じに使える:
>>> c = mk_counter()
>>> c()
0
>>> c()
1
>>> c()
2
>>> d = mk_counter(100)
>>> d()
100
>>> c()
3
>>> d()
101
>>> c()
4
ただ Python には generator がある。カウンターをつくるならたぶん generator のほうがわかりやすい。
def mk_counter_gen(starts_with: int = 0):
while True:
yield starts_with
starts_with += 1
yield を呼ぶ関数は next 関数を経由して次の値を読みだせる。(関数末尾に到達すると StopIteration 例外が送出される。これは iterator に対して for ループを回すときと同じインターフェース)
>>> e = mk_counter_gen()
>>> next(e)
0
>>> next(e)
1
>>> next(e)
2
* * *
戻って。
Python における「クロージャー」の使いどころがわからない。(Python でなくても、わからない)
この記事が気に入ったらサポートをしてみませんか?