When something goes wrong, due to incorrect code or input. When an exception occurs, the program immediately stops.

Common exceptions description
ImportError an import fails
IndexError a list is indexed with an out-of-range number
NameError an unknown variable is used. list[a]
SyntaxError the code can’t be parsed properly
TypeError a function is called on a value of an inappropriate type. list[1.0]
ValueError a function is called on a value of the correct type, but with an inappropriate value
Built-in exceptions such as ZeroDivisionErrorOSErrorStopIteration.
Third-party Errors Third-party libraries also define their own exceptions

常见Errors

若Python 遇到错误,它就会生成一些错误信息,称为“反向跟踪”。反向跟踪包含了出错消息、导致该错误的代码行号,以及导致该错误的函数调用的序列。这个序列称为“调用栈”。

以下代码一次会追踪到6->2->4==>This is the error message.

1
2
3
4
5
6
def spam(): 
bacon()
def bacon():
raise Exception('This is the error message.')

spam()

使用 try 和 except 语句,你可以更优雅地处理错误,而不是让整个程序崩溃。

只要抛出的异常没有被处理,Python 就会显示反向跟踪。但你也可以调用traceback.format_exc(),得到它的字符串形式。

1
2
3
4
5
6
7
8
9
import traceback 
try:
raise Exception('This is an error message.')
except:
errorFile = open('errorInfo.txt', 'w')
errorFile.write(traceback.format_exc()) ## 116个字符被写入到文件中
errorFile.close()
print('The traceback info was written to errorInfo.txt.')
# The traceback info was written to errorInfo.txt.
1
2
3
4
Traceback (most recent call last):
File "<ipython-input-42-3cf24af55dca>", line 3, in <module>
raise Exception('This is an error message.')
Exception: This is an error message.

Python的“断言”由 assert 语句执行。如果检查失败,就会抛出异常。我断言这个条件为真,如果不为真,程序便会抛出一个异常,比如:你的hello太多了 。

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
var = 7
print(var * "hello")
print(var / "hello")
except ZeroDivisionError as err:
print("Divided by zero",err)
except (ValueError, TypeError) as err2:
print(err2)
except:
print("Unknown occurred")
finally:
print("It`s over!")
assert(var <= 5), "Too many hellos"
1
2
3
4
5
6
7
8
9
10
11
hellohellohellohellohellohellohello
unsupported operand type(s) for /: 'int' and 'str'
It`s over!
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-13-03f060164418> in <module>
11 finally:
12 print("It`s over!")
---> 13 assert(var <= 5), "Too many hellos"

AssertionError: Too many hellos

编写一个交通信号灯的模拟程序。代表路口信号灯的数据结构是一个字典,以 ‘ns’ 和 ‘ew’ 为键,分别表示南北向和东西向的信号灯。这些键的值可以是 ‘green’、‘yellow’ 或 ‘red’ 之一。简单的代码像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
market_2nd = {'ns': 'green', 'ew': 'red'} 
def switchLights(stoplight):
for key in stoplight.keys():
if stoplight[key] == 'green':
stoplight[key] = 'yellow'
elif stoplight[key] == 'yellow':
stoplight[key] = 'red'
elif stoplight[key] == 'red':
stoplight[key] = 'green'
print(stoplight)
assert 'red' in stoplight.values(), 'Neither light is red! ' + str(stoplight)

switchLights(market_2nd)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{'ns': 'yellow', 'ew': 'green'}
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-51-bc61311a1f1e> in <module>
11 assert 'red' in stoplight.values(), 'Neither light is red! ' + str(stoplight)
12
---> 13 switchLights(market_2nd)

<ipython-input-51-bc61311a1f1e> in switchLights(stoplight)
9 stoplight[key] = 'green'
10 print(stoplight)
---> 11 assert 'red' in stoplight.values(), 'Neither light is red! ' + str(stoplight)
12
13 switchLights(market_2nd)

AssertionError: Neither light is red! {'ns': 'yellow', 'ew': 'green'}

在运行 Python 时传入-O 选项,可以禁用断言。

日志logging

启用Python的 logging 模块,可以在程序运行时,将日志信息显示在屏幕上。

比如你编写了阶乘函数,但结果不对,所以你需要输入一些日志信息,来帮助你弄清楚哪里出了问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import logging 
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')
## 写入文本
# logging.basicConfig(filename='Log.txt', level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of program')

def factorial(n):
logging.debug('Start of factorial(%s%%)' % (n))
total = 1
for i in range(n + 1):
total *= i
logging.debug('i is ' + str(i) + ', total is ' + str(total))
logging.debug('End of factorial(%s%%)' % (n))
return total

print(factorial(5))

logging.debug('End of program')

然后把for i in range(n + 1)改为for i in range(1, n + 1)即可。

我们向basicConfig()函数传入 logging.DEBUG 作为 level 关键字参数,其中DEBUG是最低的级别,日志的重要性按5 个级别对日志消息进行分类:

级别 日志函数 描述
DEBUG logging.debug() 最低级别。用于小细节。通常只有在诊断问题时,你才会关心这些消息
INFO logging.info() 用于记录程序中一般事件的信息,或确认一切工作正常
WARNING logging.warning() 用于表示可能的问题,它不会阻止程序的工作,但将来可能会
ERROR logging.error() 用于记录错误,它导致程序做某事失败
CRITICAL logging.critical() 最高级别。用于表示致命的错误,它导致或将导致程序完全停止工作

Tips: 在调试完程序后,用 logging.disable(logging.DEBUG)可以禁用日志消息。

Examples

Celsius To Fahrenheit and Fahrenheit to Celsius conversion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
while True:
CF = input("Plz input temperature in celsius(e.g. 25c) / Fahrenheit(e.g. 52f): ")
try:
if CF.endswith("C") or CF.endswith("c"):
fcelsius = float(CF[:-1])
fahrenheit = (fcelsius * 1.8) + 32
print('%.2f°C = %0.2f°F' %(fcelsius, fahrenheit))
break
elif CF.endswith("F") or CF.endswith("f"):
ffahrenheit = float(CF[:-1])
celsius = (ffahrenheit - 32) / 1.8
print('%.2f°F = %0.2f°C' %(ffahrenheit, celsius))
break
else:
print("Invalid Format Error, plz check your input! ")
except ValueError:
print("Invalid Format Error, plz check your input! ")
1
2
3
4
Plz input temperature in celsius(e.g. 25c) / Fahrenheit(e.g. 52f):  0x6f
Invalid Format Error, plz check your input!
Plz input temperature in celsius(e.g. 25c) / Fahrenheit(e.g. 52f): 036f
36.00°F = 2.22°C

Iteration

Lets see a StopIterationexample:

A triplet (x, y, z) is called pythogorian triplet if x*x + y*y == z*z.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def integers():
"""Infinite sequence of integers."""
i = 1
while True:
yield i
i = i + 1

def squares():
for i in integers():
yield i * i

def take(n, seq):
"""Returns first n values from the given sequence."""
seq = iter(seq)
result = []
try:
for i in range(n):
result.append(next(seq))
except StopIteration:
pass
return result

print(take(5, squares()))
# [1, 4, 9, 16, 25]
1
2
3
pyt = ((x, y, z) for z in integers() for y in range(1, z) for x in range(1, y) if x*x + y*y == z*z)
take(10, pyt)
# [(3, 4, 5), (6, 8, 10), (5, 12, 13), (9, 12, 15), (8, 15, 17), (12, 16, 20), (15, 20, 25), (7, 24, 25), (10, 24, 26), (20, 21, 29)]

REFERENCES