Skip to content

Commit 5c2b392

Browse files
committed
error
1 parent a44cb16 commit 5c2b392

5 files changed

Lines changed: 286 additions & 2 deletions

File tree

215.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ yield语句的作用,就是在调用的时候返回相应的值。详细剖析
253253

254254
------
255255

256-
[总目录](./index.md)   |   [上节:迭代器](./214.md)   |   [下节:异常](./216.md)
256+
[总目录](./index.md)   |   [上节:迭代器](./214.md)   |   [下节:错误和异常(1)](./216.md)
257257

258258
如果你认为有必要打赏我,请通过支付宝:**[email protected]**,不胜感激。
259259

216.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
>因为各人必担当自己的担子。在道理上受教的,当把一切需用的供给施教的人。不要自欺,神是轻慢不得的。人种的是什么,收的也是什么。顺着情欲撒种的,必从情欲收败坏;顺着圣灵撒种的,必从圣灵收永生。我们行善,不可丧志,若不灰心,到了时候就要收成。(GALATIANS 6:5-9)
2+
3+
#错误和异常(1)
4+
5+
虽然在前面的学习中,已经遇到了错误和异常问题,但是一直没有很认真的研究它。现在来近距离观察错误和异常。
6+
7+
##错误
8+
9+
python中的错误之一是语法错误(syntax errors),比如:
10+
11+
>>> for i in range(10)
12+
File "<stdin>", line 1
13+
for i in range(10)
14+
^
15+
SyntaxError: invalid syntax
16+
17+
上面那句话因为缺少冒号`:`,导致解释器无法解释,于是报错。这个报错行为是由python的语法分析器完成的,并且检测到了错误所在文件和行号(`File "<stdin>", line 1`),还以向上箭头`^`标识错误位置(后面缺少`:`),最后显示错误类型。
18+
19+
错误之二是在没有语法错误之后,会出现逻辑错误。逻辑错误可能会由于不完整或者不合法的输入导致,也可能是无法生成、计算等,或者是其它逻辑问题。
20+
21+
当python检测到一个错误时,解释器就无法继续执行下去,于是抛出异常。
22+
23+
##异常
24+
25+
看一个异常(让0做分母了,这是小学生都相信会有异常的):
26+
27+
>>> 1/0
28+
Traceback (most recent call last):
29+
File "<stdin>", line 1, in <module>
30+
ZeroDivisionError: integer division or modulo by zero
31+
32+
当python抛出异常的时候,首先有“跟踪记录(Traceback)”,还可以给它取一个更优雅的名字“回溯”。后面显示异常的详细信息。异常所在位置(文件、行、在某个模块)。
33+
34+
最后一行是错误类型以及导致异常的原因。
35+
36+
下表中列出常见的异常
37+
38+
|异常 | 描述|
39+
|-----|-----|
40+
|NameError |尝试访问一个没有申明的变量|
41+
|ZeroDivisionError | 除数为0|
42+
|SyntaxError| 语法错误|
43+
|IndexError| 索引超出序列范围|
44+
|KeyError| 请求一个不存在的字典关键字|
45+
|IOError| 输入输出错误(比如你要读的文件不存在)|
46+
|AttributeError| 尝试访问未知的对象属性|
47+
48+
为了能够深入理解,依次举例,展示异常的出现条件和结果。
49+
50+
###NameError
51+
52+
>>> bar
53+
Traceback (most recent call last):
54+
File "<stdin>", line 1, in <module>
55+
NameError: name 'bar' is not defined
56+
57+
python中变量需要初始化,即要赋值。虽然不需要像某些语言那样声明,但是要赋值先。因为变量相当于一个标签,要把它贴到对象上才有意义。
58+
59+
###ZeroDivisionError
60+
61+
>>> 1/0
62+
Traceback (most recent call last):
63+
File "<stdin>", line 1, in <module>
64+
ZeroDivisionError: integer division or modulo by zero
65+
66+
貌似这样简单的错误时不会出现的,但在实际情境中,可能没有这么容易识别,所以,依然要小心为妙。
67+
68+
###SyntaxError
69+
70+
>>> for i in range(10)
71+
File "<stdin>", line 1
72+
for i in range(10)
73+
^
74+
SyntaxError: invalid syntax
75+
76+
这种错误发生在python代码编译的时候,当编译到这一句时,解释器不能讲代码转化为python字节码,就报错。只有改正才能继续。所以,它是在程序运行之前就会出现的(如果有错)。现在有不少编辑器都有语法校验功能,在你写代码的时候就能显示出语法的正误,这多少会对编程者有帮助。
77+
78+
###IndexError
79+
80+
>>> a = [1,2,3]
81+
>>> a[4]
82+
Traceback (most recent call last):
83+
File "<stdin>", line 1, in <module>
84+
IndexError: list index out of range
85+
86+
>>> d = {"python":"itdiffer.com"}
87+
>>> d["java"]
88+
Traceback (most recent call last):
89+
File "<stdin>", line 1, in <module>
90+
KeyError: 'java'
91+
92+
这两个都属于“鸡蛋里面挑骨头”类型,一定得报错了。不过在编程实践中,特别是循环的时候,常常由于循环条件设置不合理出现这种类型的错误。
93+
94+
###IOError
95+
96+
>>> f = open("foo")
97+
Traceback (most recent call last):
98+
File "<stdin>", line 1, in <module>
99+
IOError: [Errno 2] No such file or directory: 'foo'
100+
101+
如果你确认有文件,就一定要把路径写正确,因为你并没有告诉python对你的computer进行全身搜索,所以,python会按照你指定位置去找,找不到就异常。
102+
103+
###AttributeError
104+
105+
>>> class A(object): pass
106+
...
107+
>>> a = A()
108+
>>> a.foo
109+
Traceback (most recent call last):
110+
File "<stdin>", line 1, in <module>
111+
AttributeError: 'A' object has no attribute 'foo'
112+
113+
属性不存在。这种错误前面多次见到。
114+
115+
其实,python内建的异常也不仅仅上面几个,上面只是列出常见的异常中的几个。比如还有:
116+
117+
>>> range("aaa")
118+
Traceback (most recent call last):
119+
File "<stdin>", line 1, in <module>
120+
TypeError: range() integer end argument expected, got str.
121+
122+
总之,如果读者在调试程序的时候遇到了异常,不要慌张,这是好事情,是python在帮助你修改错误。只要认真阅读异常信息,再用`dir()``help()`或者官方网站文档、google等来协助,一定能解决问题。
123+
124+
##处理异常
125+
126+
在一段程序中,为了能够让程序健壮,必须要处理异常。举例:
127+
128+
#!/usr/bin/env python
129+
# coding=utf-8
130+
131+
while 1:
132+
print "this is a division program."
133+
c = raw_input("input 'c' continue, otherwise logout:")
134+
if c == 'c':
135+
a = raw_input("first number:")
136+
b = raw_input("second number:")
137+
try:
138+
print float(a)/float(b)
139+
print "*************************"
140+
except ZeroDivisionError:
141+
print "The second number can't be zero!"
142+
print "*************************"
143+
else:
144+
break
145+
146+
运行这段程序,显示如下过程:
147+
148+
$ python 21601.py
149+
this is a division program.
150+
input 'c' continue, otherwise logout:c
151+
first number:5
152+
second number:2
153+
2.5
154+
*************************
155+
this is a division program.
156+
input 'c' continue, otherwise logout:c
157+
first number:5
158+
second number:0
159+
The second number can't be zero!
160+
*************************
161+
this is a division program.
162+
input 'c' continue, otherwise logout:d
163+
$
164+
165+
从运行情况看,当在第二个数,即除数为0时,程序并没有因为这个错误而停止,而是给用户一个友好的提示,让用户有机会改正错误。这完全得益于程序中“处理异常”的设置,如果没有“处理异常”,异常出现,就会导致程序终止。
166+
167+
处理异常的方式之一,使用`try...except...`
168+
169+
对于上述程序,只看try和except部分,如果没有异常发生,except子句在try语句执行之后被忽略;如果try子句中有异常可,该部分的其它语句被忽略,直接跳到except部分,执行其后面指定的异常类型及其子句。
170+
171+
except后面也可以没有任何异常类型,即无异常参数。如果这样,不论try部分发生什么异常,都会执行except。
172+
173+
在except子句中,可以根据异常或者别的需要,进行更多的操作。比如:
174+
175+
#!/usr/bin/env python
176+
# coding=utf-8
177+
178+
class Calculator(object):
179+
is_raise = False
180+
def calc(self, express):
181+
try:
182+
return eval(express)
183+
except ZeroDivisionError:
184+
if self.is_raise:
185+
print "zero can not be division."
186+
else:
187+
raise
188+
189+
在这里,应用了一个函数`eval()`,它的含义是:
190+
191+
eval(...)
192+
eval(source[, globals[, locals]]) -> value
193+
194+
Evaluate the source in the context of globals and locals.
195+
The source may be a string representing a Python expression
196+
or a code object as returned by compile().
197+
The globals must be a dictionary and locals can be any mapping,
198+
defaulting to the current globals and locals.
199+
If only globals is given, locals defaults to it.
200+
201+
例如:
202+
203+
>>> eval("3+5")
204+
8
205+
206+
另外,在except子句中,有一个`raise`,作为单独一个语句。它的含义是将异常信息抛出。并且,except子句用了一个判断语句,根据不同的情况确定走不同分支。
207+
208+
if __name__ == "__main__":
209+
c = Calculator()
210+
print c.calc("8/0")
211+
212+
这时候`is_raise = False`,则会:
213+
214+
$ python 21602.py
215+
Traceback (most recent call last):
216+
File "21602.py", line 17, in <module>
217+
print c.calc("8/0")
218+
File "21602.py", line 8, in calc
219+
return eval(express)
220+
File "<string>", line 1, in <module>
221+
ZeroDivisionError: integer division or modulo by zero
222+
223+
如果将`is_raise`的值改为True,就是这样了:
224+
225+
if __name__ == "__main__":
226+
c = Calculator()
227+
c.is_raise = True #通过实例属性修改
228+
print c.calc("8/0")
229+
230+
运行结果:
231+
232+
$ python 21602.py
233+
zero can not be division.
234+
None
235+
236+
最后的None是`c.calc("8/0")`的返回值,因为有`print c.calc("8/0")`,所以被打印出来。
237+
238+
------
239+
240+
[总目录](./index.md)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[上节:生成器](./215.md)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[下节:错误和异常(2)](./217.md)
241+
242+
如果你认为有必要打赏我,请通过支付宝:**[email protected]**,不胜感激。

2code/21601.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env python
2+
# coding=utf-8
3+
4+
"""
5+
try... except
6+
"""
7+
8+
while 1:
9+
print "this is a division program."
10+
c = raw_input("input 'c' continue, otherwise logout:")
11+
if c == 'c':
12+
a = raw_input("first number:")
13+
b = raw_input("second number:")
14+
try:
15+
print float(a)/float(b)
16+
print "*************************"
17+
except ZeroDivisionError:
18+
print "The second number can't be zero!"
19+
print "*************************"
20+
else:
21+
break
22+

2code/21602.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env python
2+
# coding=utf-8
3+
4+
class Calculator(object):
5+
is_raise = False
6+
def calc(self, express):
7+
try:
8+
return eval(express)
9+
except ZeroDivisionError:
10+
if self.is_raise:
11+
print "zero can not be division."
12+
else:
13+
raise
14+
15+
if __name__ == "__main__":
16+
c = Calculator()
17+
c.is_raise = True
18+
print c.calc("8/0")

index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@
7171
9. [迭代器](./214.md)==>迭代器方法`__iter__`,`netx()`
7272
10. [生成器](./215.md)==>生成器定义,yield,生成器方法
7373

74-
##第伍章 异常
74+
##第伍章 错误和异常
75+
76+
1. [错误和异常(1)](./216.md)==>什么是错误和异常,常见异常类型,处理异常(try...except...)
7577

7678
##第陆章 模块
7779

0 commit comments

Comments
 (0)