回答編集履歴

5

追記

2018/09/24 08:05

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -112,7 +112,7 @@
112
112
 
113
113
  exec(f'from {module_name} import answer as _answer')
114
114
 
115
- answer = locals()['_answer']
115
+ answer = locals()['_answer'] # eval('_answer') でも可
116
116
 
117
117
 
118
118
 
@@ -212,7 +212,7 @@
212
212
 
213
213
  ---
214
214
 
215
- 見当の末、判明したエラーの要因は次のとおりです。
215
+ 検討の末、判明したエラーの要因は次のとおりです。
216
216
 
217
217
  - ローカルな名前空間を持つブロックで
218
218
 
@@ -222,7 +222,7 @@
222
222
 
223
223
 
224
224
 
225
- こっちはエラーを吐きますが、 [Wandbox](https://wandbox.org/permlink/mLyOmRPV9qzmkOvv)
225
+ こっちは`NameError: name 'answer' is not defined`を吐きますが、 [Wandbox](https://wandbox.org/permlink/mLyOmRPV9qzmkOvv)
226
226
 
227
227
  ```Python
228
228
 

4

追記

2018/09/24 08:05

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -208,7 +208,73 @@
208
208
 
209
209
 
210
210
 
211
- 結論
211
+ 原因
212
+
213
+ ---
214
+
215
+ 見当の末、判明したエラーの要因は次のとおりです。
216
+
217
+ - ローカルな名前空間を持つブロックで
218
+
219
+ - execに依って代入やそれに準ずる文を書き
220
+
221
+ - それ以降に同名の変数を宣言する場合
222
+
223
+
224
+
225
+ こっちはエラーを吐きますが、 [Wandbox](https://wandbox.org/permlink/mLyOmRPV9qzmkOvv)
226
+
227
+ ```Python
228
+
229
+ def main():
230
+
231
+ exec('answer = 42')
232
+
233
+ answer = eval('answer')
234
+
235
+
236
+
237
+ return answer
238
+
239
+
240
+
241
+ print(
242
+
243
+ main()
244
+
245
+ )
246
+
247
+ ```
248
+
249
+
250
+
251
+ こっちは吐かないです。[Wandbox](https://wandbox.org/permlink/tepA467Ua4rlrqCO)
252
+
253
+ ```Python
254
+
255
+ def main():
256
+
257
+ exec('_answer = 42')
258
+
259
+ answer = eval('_answer')
260
+
261
+
262
+
263
+ return answer
264
+
265
+
266
+
267
+ print(
268
+
269
+ main()
270
+
271
+ )
272
+
273
+ ```
274
+
275
+
276
+
277
+ 最終的な結論
212
278
 
213
279
  ---
214
280
 

3

追記

2018/09/24 08:02

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -96,4 +96,120 @@
96
96
 
97
97
 
98
98
 
99
+ グローバル空間の汚染を避ける
100
+
101
+ ---
102
+
103
+ もう少し検討した結果、次のように書いた方がより正確であることに気付きました。
104
+
105
+ ```Python
106
+
107
+ module_name = 'module'
108
+
109
+
110
+
111
+ def main(module_name):
112
+
113
+ exec(f'from {module_name} import answer as _answer')
114
+
115
+ answer = locals()['_answer']
116
+
117
+
118
+
119
+ print(answer)
120
+
121
+
122
+
123
+ main(module_name)
124
+
125
+ print(answer)
126
+
127
+ ```
128
+
129
+
130
+
131
+ **実行結果** [Wandbox](https://wandbox.org/permlink/x8g174c7JiYRMvpb)
132
+
133
+ ```plain
134
+
135
+ 42
136
+
137
+ Traceback (most recent call last):
138
+
139
+ File "prog.py", line 10, in <module>
140
+
141
+ print(answer)
142
+
143
+ NameError: name 'answer' is not defined
144
+
145
+ ```
146
+
147
+
148
+
149
+ スコープ外でちゃんとエラーになってくれるところが良さげです。
150
+
151
+
152
+
153
+ なお、`_answer`をいちいち経由しているのにも理由があります。
154
+
155
+ ```Python
156
+
157
+ module_name = 'module'
158
+
159
+
160
+
161
+ def main(module_name):
162
+
163
+ exec(f'from {module_name} import answer')
164
+
165
+ answer = locals()['answer']
166
+
167
+
168
+
169
+ print(answer)
170
+
171
+
172
+
173
+ main(module_name)
174
+
175
+ # print(answer)
176
+
177
+ ```
178
+
179
+
180
+
181
+ **実行結果** [Wandbox](https://wandbox.org/permlink/DjLeePr4lZxkrznq)
182
+
183
+ ```plain
184
+
185
+ Traceback (most recent call last):
186
+
187
+ File "prog.py", line 9, in <module>
188
+
189
+ main(module_name)
190
+
191
+ File "prog.py", line 5, in main
192
+
193
+ answer = locals()['answer']
194
+
195
+ KeyError: 'answer'
196
+
197
+ ```
198
+
199
+
200
+
201
+ Pythonインタプリタは関数内の代入を前もって舐めているので、
202
+
203
+ 未初期化状態であるanswerをローカル辞書に登録することを避けるのでしょうね。
204
+
205
+
206
+
207
+ あくまで推測の域を出ませんが。
208
+
209
+
210
+
211
+ 結論
212
+
213
+ ---
214
+
99
215
  やはりexecやevalを利用するのは最終手段ですね。

2

追記

2018/09/24 07:40

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -1,4 +1,12 @@
1
1
  おもしろい現象ですね。
2
+
3
+ このようなときは、ミニマムなコードで状況を再現し、原因を絞り込むのが常套手段です。
4
+
5
+
6
+
7
+ エラーの再現
8
+
9
+ ---
2
10
 
3
11
  次のようなコードで状況が再現しました。[Wandbox](https://wandbox.org/permlink/09T7CCwlKY57b9NT)
4
12
 
@@ -35,6 +43,10 @@
35
43
  ```
36
44
 
37
45
 
46
+
47
+ エラーの条件の検討と、解決
48
+
49
+ ---
38
50
 
39
51
  一方、main.pyを次のように書いたときには問題なく動作します。[Wandbox](https://wandbox.org/permlink/W1a5jFEkZtjS9jAz)
40
52
 

1

追記

2018/09/24 07:21

投稿

LouiS0616
LouiS0616

スコア35660

test CHANGED
@@ -81,3 +81,7 @@
81
81
  main(module_name)
82
82
 
83
83
  ```
84
+
85
+
86
+
87
+ やはりexecやevalを利用するのは最終手段ですね。