回答編集履歴

2

コードを追加

2018/02/13 00:47

投稿

frodo821
frodo821

スコア322

test CHANGED
@@ -1,3 +1,79 @@
1
1
  withステートメントは`__enter__`関数と`__exit__`関数のラッパーになっていますが、この内`__enter__`関数内でエラーが発生した場合に`__exit__`関数は呼ばれません(python3.6.3で確認)。
2
2
 
3
3
  この場合は安全のために、withを使わずに明示的にオープン・クローズをした方がいいかと思います。
4
+
5
+ 修正例としてはこのようなコードになります。
6
+
7
+ ```python
8
+
9
+ import urllib.request
10
+
11
+
12
+
13
+ def check_status(url):
14
+
15
+ try:
16
+
17
+ response = urllib.request.urlopen(url, timeout=10)
18
+
19
+ return response.code
20
+
21
+ except urllib.error.HTTPError as e:
22
+
23
+ return e.code
24
+
25
+ except Exception as e:
26
+
27
+ print(str(e))
28
+
29
+ return -1
30
+
31
+ finally:
32
+
33
+ response.close()
34
+
35
+
36
+
37
+ status = check_status('https://www.hoge.com/')
38
+
39
+ print("access status:", status)
40
+
41
+ if status != 200:
42
+
43
+ print("access error.")
44
+
45
+ # 疎通失敗時のアクション
46
+
47
+ ```
48
+
49
+ `urlopen`関数の怖いところは、標準の`open`や`socket.socket.connect`などと違って名前解決が出来なかった、そもそもソケットが作れなかった等の場合を除きエラーが発生するときには既に接続が確立していることです。
50
+
51
+ もし、標準以外のライブラリを使うことに抵抗が無いなら`urllib`ではなく`requests`等の高水準ライブラリを使うとよいと思います。
52
+
53
+ 一応サンプルコードもおいときますね。
54
+
55
+ ```python
56
+
57
+ from requests import get
58
+
59
+
60
+
61
+ def check_status(url):
62
+
63
+ #hostが見つからない場合、404が返ります
64
+
65
+ return get(url, timeout=10).status_code
66
+
67
+
68
+
69
+ status = check_status('https://www.hoge.com/')
70
+
71
+ print("access status:", status)
72
+
73
+ if status != 200:
74
+
75
+ print("access error.")
76
+
77
+ # 疎通失敗時のアクション
78
+
79
+ ```

1

情報を追加

2018/02/13 00:47

投稿

frodo821
frodo821

スコア322

test CHANGED
@@ -1,3 +1,3 @@
1
- withステートメントは`__enter__`関数と`__exit__`関数のラッパーになっていますが、この内`__enter__`関数内でエラーが発生した場合に`__exit__`関数は呼ばれません。
1
+ withステートメントは`__enter__`関数と`__exit__`関数のラッパーになっていますが、この内`__enter__`関数内でエラーが発生した場合に`__exit__`関数は呼ばれません(python3.6.3で確認)
2
2
 
3
3
  この場合は安全のために、withを使わずに明示的にオープン・クローズをした方がいいかと思います。