すでにそのものズバリの回答がついているのと、個人的にあまり関数閉包が好きではないので、「似たやり方」をいくつか。
普通にクラスにする
けっきょく、欲しいものは閉じた名前空間のあるオブジェクト。普通に考えたらインスタンスです。
python
1class Hoge:
2 def __init__(self, i):
3 self.i = i
4
5 def f(self, x):
6 return x + self.i
7
8hlst = []
9for i in range(5):
10 h = Hoge(i)
11 hlst.append(h)
12
13for h in hlst:
14 print(h.f(0))
15
16""" =>
170
181
192
203
214
22"""
23
この規模だと見栄えがしませんが、ある程度大きいものを作るならいい方法です。
引数のデフォルト値を活用する
デフォルト値が実行時(関数定義時)評価なのがキモ。
python
1flst = []
2for i in range(5):
3 def f(x, i=i):
4 return x + i
5 flst.append(f)
6
7for f in flst:
8 print(f(0))
9"""
100
111
122
133
144
15"""
16
単に外のスコープに置く
python
1a = increment(1)
2b = increment(2)
3c = increment(3)
4def func(x, y):
5 return x * a * b + y * c
これで済むなら別にこれでも良いのでは? と思います。
関数オブジェクトの属性に押し込む
この方法は汚いので非推奨ですが・・・
python
1flst = []
2for i in range(5):
3 def f(x):
4 return x + f.i
5 f.i = i
6 flst.append(f)
7
8for f in flst:
9 print(f(0))
10
11""" =>
120
131
142
153
164
17"""
記述量だけならクロージャより少なくて済むのが強みです。引数のデフォルト値を使う方法には負けますが。
関数に呼び出しをまたいで変化する状態を持たせるような用途だと、この方法は輝きます。デフォルト値では(たぶん)できないからです。
これとクロージャでカウンタを書いた例。
python
1# クロージャ版
2def make_f(init):
3 def f():
4 nonlocal init # 必須
5 init += 1
6 return init
7 return f
8
9f = make_f(0)
10for i in range(5):
11 print(f())
12""" =>
131
142
153
164
175
18"""
19
20# 属性版
21def f():
22 f.init += 1
23 return f.init
24f.init = 0
25
26for i in range(5):
27 print(f())
28""" =>
291
302
313
324
335
34"""
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/29 09:58