回答編集履歴

2

質問修正を確認

2019/03/30 04:52

投稿

ikedas
ikedas

スコア4337

test CHANGED
@@ -82,3 +82,5 @@
82
82
 
83
83
  ところで、ご質問のとおりエラー時に再帰的に`throw_request()`を呼び出せたとして、ユーザエージェントを変えてもアクセス拒否されたとしたら、再帰がとまらなくなりますね。明確な**終了条件のない再帰呼び出し**にはそういう危険があります。ここは再帰ではなく、単にもう一度リクエストを発行してみるだけのほうがいいかもしれません。
84
84
 
85
+ \[3/30追記] 質問文で、再帰に終了条件を設けて無限の再帰にならないようにされたことを確認しました。
86
+

1

質問への補足追記後の回答

2019/03/30 04:52

投稿

ikedas
ikedas

スコア4337

test CHANGED
@@ -15,3 +15,70 @@
15
15
 
16
16
  これは最初の質問と話題が離れすぎるので、別の質問にしていただいたほうがいいとおもいます。
17
17
 
18
+ # 質問への補足追記後の回答
19
+
20
+ まず【質問1】の回答に補足です。`HTTPError`は`URLError`の基底クラスなので、次のようにも書けます (派生クラス→基底クラスの順で例外を捕捉する`except`節を書く)。`code`属性を持っているかどうかを調べるよりもすっきりしますし、汎用性があります (将来、`code`属性をもつ別の例外が追加されるかもしれませんから)。
21
+
22
+ ```python
23
+ def throw_request(url, req=None):
24
+ if req is None:
25
+ req = Request(url)
26
+ try:
27
+ res = urlopen(req)
28
+ except HTTPError as e:
29
+ print('raise HTTPError')
30
+ ...
31
+
32
+ if e.code == 403:
33
+ ...
34
+
35
+ sys.exit(1)
36
+ except URLError as e:
37
+ print('raise URLError')
38
+ ...
39
+
40
+ sys.exit(1)
41
+ else:
42
+ print("success Request")
43
+ ...
44
+
45
+ return res
46
+ ```
47
+
48
+ で、【質問2】ですが、「例外が発生したか否かにかかわらず実行したい」というものは`finally`節に書きます。例外が`except`節で捕捉されればその節の処理が実行され、そのあとで`finally`節の処理が実行されます (成功の場合は`finally`節だけ実行されます)。
49
+
50
+ ちなみに今回のコードの場合、例外発生時の処理の最後に`sys.exit(1)`でプログラムを終了するように書いてありますが、`finally`節で最終的に`return`して呼び出し元に戻るので、これらはいらないです (あってもききません)。
51
+
52
+ ```python
53
+ def throw_request(url, req=None):
54
+ if req is None:
55
+ req = Request(url)
56
+ try:
57
+ res = urlopen(req)
58
+ except HTTPError as e:
59
+ print('raise HTTPError')
60
+ ...
61
+
62
+ if e.code == 403:
63
+ ...
64
+ throw_request(url, req)
65
+
66
+ #sys.exit(1)
67
+ except URLError as e:
68
+ print('raise URLError')
69
+ ...
70
+
71
+ #sys.exit(1)
72
+ finally:
73
+ print("success Request")
74
+ ...
75
+
76
+ return res
77
+ ```
78
+
79
+ 以上の説明のうち、例外処理の言語仕様については、Python言語仕様の「[例外](https://docs.python.org/ja/3/reference/executionmodel.html#exceptions)」節をみてください。
80
+
81
+ ---
82
+
83
+ ところで、ご質問のとおりエラー時に再帰的に`throw_request()`を呼び出せたとして、ユーザエージェントを変えてもアクセス拒否されたとしたら、再帰がとまらなくなりますね。明確な**終了条件のない再帰呼び出し**にはそういう危険があります。ここは再帰ではなく、単にもう一度リクエストを発行してみるだけのほうがいいかもしれません。
84
+