質問するログイン新規登録

回答編集履歴

2

追記

2018/08/26 00:13

投稿

hayataka2049
hayataka2049

スコア30939

answer CHANGED
@@ -1,6 +1,6 @@
1
1
  すでにそのものズバリの回答がついているのと、個人的にあまり関数閉包が好きではないので、「似たやり方」をいくつか。
2
2
 
3
- - 普通にクラスにする
3
+ ### 普通にクラスにする
4
4
  けっきょく、欲しいものは閉じた名前空間のあるオブジェクト。普通に考えたらインスタンスです。
5
5
 
6
6
  ```python
@@ -32,7 +32,7 @@
32
32
  この規模だと見栄えがしませんが、ある程度大きいものを作るならいい方法です。
33
33
 
34
34
 
35
- - 引数のデフォルト値を活用する
35
+ ### 引数のデフォルト値を活用する
36
36
  デフォルト値が実行時(関数定義時)評価なのがキモ。
37
37
 
38
38
  ```python
@@ -54,7 +54,7 @@
54
54
 
55
55
  ```
56
56
 
57
- - 単に外のスコープに置く
57
+ ### 単に外のスコープに置く
58
58
 
59
59
  ```python
60
60
  a = increment(1)
@@ -66,7 +66,7 @@
66
66
 
67
67
  これで済むなら別にこれでも良いのでは? と思います。
68
68
 
69
- - 関数オブジェクトの属性に押し込む
69
+ ### 関数オブジェクトの属性に押し込む
70
70
  この方法は汚いので非推奨ですが・・・
71
71
 
72
72
  ```python
@@ -89,4 +89,45 @@
89
89
  """
90
90
  ```
91
91
 
92
- 記述量だけならクロージャより少なくて済むのが強みです。
92
+ 記述量だけならクロージャより少なくて済むのが強みです。引数のデフォルト値を使う方法には負けますが。
93
+
94
+ 関数に呼び出しをまたいで変化する状態を持たせるような用途だと、この方法は輝きます。デフォルト値では(たぶん)できないからです。
95
+
96
+ これとクロージャでカウンタを書いた例。
97
+
98
+ ```python
99
+ # クロージャ版
100
+ def make_f(init):
101
+ def f():
102
+ nonlocal init # 必須
103
+ init += 1
104
+ return init
105
+ return f
106
+
107
+ f = make_f(0)
108
+ for i in range(5):
109
+ print(f())
110
+ """ =>
111
+ 1
112
+ 2
113
+ 3
114
+ 4
115
+ 5
116
+ """
117
+
118
+ # 属性版
119
+ def f():
120
+ f.init += 1
121
+ return f.init
122
+ f.init = 0
123
+
124
+ for i in range(5):
125
+ print(f())
126
+ """ =>
127
+ 1
128
+ 2
129
+ 3
130
+ 4
131
+ 5
132
+ """
133
+ ```

1

修正

2018/08/26 00:13

投稿

hayataka2049
hayataka2049

スコア30939

answer CHANGED
@@ -1,7 +1,7 @@
1
1
  すでにそのものズバリの回答がついているのと、個人的にあまり関数閉包が好きではないので、「似たやり方」をいくつか。
2
2
 
3
3
  - 普通にクラスにする
4
- けっきょく、欲しいものは閉じた名前空間。普通に考えたらインスタンスです。
4
+ けっきょく、欲しいものは閉じた名前空間のあるオブジェクト。普通に考えたらインスタンスです。
5
5
 
6
6
  ```python
7
7
  class Hoge: