-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path02.handlerror.py
More file actions
231 lines (200 loc) · 7.48 KB
/
02.handlerror.py
File metadata and controls
231 lines (200 loc) · 7.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
######################################Error Handling#####################################
# In the process of running the program, if an error occurs, an error code can be returned by agreement in advance,
# so that you will know whether there is an error and the reason caused the error. It is very common to return error
# codes in calls provided by the os.
# For example, a function that opens a file open() returns the file descriptor (that is, an integer) when successful,
# and returns when there is an error -1.
# It is very inconvenient to use the error code to indicate whether there is an error, because the normal result that
# the function itself should return is mixed with the error code, so the caller must use a lot of code to determine
# whether there is an error:
# err.py
def foo(s):
return 10 / int(s) #ZeroDivisionError: division by zero
def bar(s):
return foo(s) * 2
def main():
bar(0)
# main() #ZeroDivisionError: division by zero
# Once an error occurs, it must be reported level by level until a function can handle the error (for example,
# output an error message to the user).
# So high-level languages usually have a built-in set try...except...finally...of error handling mechanisms, and Python
# is no exception.
#########################################try############################################
# Let's use an example to see try the mechanism:
def fun(n):
try:
print('try...')
r = 10 / n
print('result:', r)
except ZeroDivisionError as e:
print('except:', e)
except TypeError as e:
print('except:',e)
finally:
print('finally...')
print('END')
fun(0)
# try...
# except: division by zero
# finally...
# END
fun(1)
# try...
# result: 10.0
# finally...
# END
fun('a')
# try...
# except: unsupported operand type(s) for /: 'int' and 'str'
# finally...
# END
print('\n')
# In addition, if no error occurs, you can except add one after the statement block else, when no error occurs,
# the else statement will be executed automatically:
def fun(n):
try:
print('try...')
r = 10 / int(n)
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
else:
print('no error!')
finally:
print('finally...')
print('END')
fun(1)
# try...
# result: 10.0
# no error!
# finally...
# END
fun('a')
#try...
# ValueError: invalid literal for int() with base 10: 'a'
# finally...
# END
print('\n')
# There is also a huge advantage of using try...except catching errors, that is, you can call across multiple layers,
# such as function main() calls bar(), bar() calls foo(), and the result is foo() an error. At this time, as long as it
# main() is caught, it can be processed:
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main(n):
try:
bar(n)
except Exception as e:
print('Error:', e)
finally:
print('finally...')
main('0')
# Error: division by zero
# finally...
main('s')
# Error: invalid literal for int() with base 10: 's'
# finally...
# That is, you don't need to catch errors at every possible place, just at the appropriate level. try...except...finally
# In this way, the trouble of writing is greatly reduced .
print('\n')
#######################################call stack##########################################
# If the error is not caught, it just keeps going up and is caught by the Python interpreter, prints an error message,
# and the program exits.
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
bar('0')
# main() # Traceback (most recent call last):
print('\n')
# The outputs are as follows:
# Traceback (most recent call last):
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 130, in <module>
# main()
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 128, in main
# bar('0')
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 125, in bar
# return foo(s) * 2
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 122, in foo
# return 10 / int(s)
# ZeroDivisionError: division by zero
# When an error occurs, be sure to analyze the wrong call stack information in order to locate the wrong location.
####################################### log error ###########################################
# If you don't catch the error, you can have the Python interpreter print the error stack, but the program is terminated.
# Now that we can catch the error, we can print the error stack, analyze the cause of the error, and let the program
# continue.
# Python's built-in logging module makes logging error messages very easy:
import logging
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except Exception as e:
logging.exception(e)
print('END')
main()
# ERROR:root:division by zero
# Traceback (most recent call last):
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 160, in main
# bar('0')
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 156, in bar
# return foo(s) * 2
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 153, in foo
# return 10 / int(s)
# ZeroDivisionError: division by zero
# END
# Through configuration, loggingerrors can also be recorded in the log file, which is convenient for later investigation.
print('\n')
#######################################throw error########################################
# Because errors are classes, catching an error is catching an instance of that class. So errors are not created
# out of thin air, but are intentionally created and thrown. Python's built-in functions throw many types of errors,
# and functions we write ourselves can throw errors as well.
# If you want to throw an error, you can first define an error class according to your needs, choose a good inheritance
# relationship, and then use the raise statement to throw an error instance:
class FooError(ValueError):
pass
def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n
# foo('0')
# Traceback (most recent call last):
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 195, in <module>
# foo('0')
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 192, in foo
# raise FooError('invalid value: %s' % s)
# __main__.FooError: invalid value: 0
# Only define our own error types when necessary. If you can choose one of Python's built-in error types
# (eg ValueError, TypeError), try to use Python's built-in error types.
print('\n')
# Finally, let's look at another way of error handling:
def foo(s):
n = int(s)
if n==0:
raise ValueError('invalid value: %s' % s)
return 10 / n
def bar():
try:
foo('0')
except ValueError as e:
print('ValueError!')
raise
bar()
# The outputs are as follows:
# ValueError!
# Traceback (most recent call last):
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 222, in <module>
# bar()
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 217, in bar
# foo('0')
# File "C:\workspace\Python\python_tutorials\10_debug\2.handlerror.py", line 212, in foo
# raise ValueError('invalid value: %s' % s)
# ValueError: invalid value: 0