Home Backend Development Python Tutorial 解析Python中的异常处理

解析Python中的异常处理

Jun 10, 2016 pm 03:14 PM
python

在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因。在操作系统提供的调用中,返回错误码非常常见。比如打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1。

用错误码来表示是否出错十分不便,因为函数本身应该返回的正常结果和错误码混在一起,造成调用者必须用大量的代码来判断是否出错:

1

2

3

4

5

6

7

8

9

10

11

12

13

def foo():

 r = some_function()

 if r==(-1):

  return (-1)

 # do something

 return r

 

def bar():

 r = foo()

 if r==(-1):

  print 'Error'

 else:

  pass

Copy after login

一旦出错,还要一级一级上报,直到某个函数可以处理该错误(比如,给用户输出一个错误信息)。

所以高级语言通常都内置了一套try...except...finally...的错误处理机制,Python也不例外。
try

让我们用一个例子来看看try的机制:

1

2

3

4

5

6

7

8

9

try:

 print 'try...'

 r = 10 / 0

 print 'result:', r

except ZeroDivisionError, e:

 print 'except:', e

finally:

 print 'finally...'

print 'END'

Copy after login

当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。

上面的代码在计算10 / 0时会产生一个除法运算错误:

1

2

3

4

try...

except: integer division or modulo by zero

finally...

END

Copy after login

从输出可以看到,当错误发生时,后续语句print 'result:', r不会被执行,except由于捕获到ZeroDivisionError,因此被执行。最后,finally语句被执行。然后,程序继续按照流程往下走。

如果把除数0改成2,则执行结果如下:

1

2

3

4

try...

result: 5

finally...

END

Copy after login

由于没有错误发生,所以except语句块不会被执行,但是finally如果有,则一定会被执行(可以没有finally语句)。

你还可以猜测,错误应该有很多种类,如果发生了不同类型的错误,应该由不同的except语句块处理。没错,可以有多个except来捕获不同类型的错误:

1

2

3

4

5

6

7

8

9

10

11

try:

 print 'try...'

 r = 10 / int('a')

 print 'result:', r

except ValueError, e:

 print 'ValueError:', e

except ZeroDivisionError, e:

 print 'ZeroDivisionError:', e

finally:

 print 'finally...'

print 'END'

Copy after login

int()函数可能会抛出ValueError,所以我们用一个except捕获ValueError,用另一个except捕获ZeroDivisionError。

此外,如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:

1

2

3

4

5

6

7

8

9

10

11

12

13

try:

 print 'try...'

 r = 10 / int('a')

 print 'result:', r

except ValueError, e:

 print 'ValueError:', e

except ZeroDivisionError, e:

 print 'ZeroDivisionError:', e

else:

 print 'no error!'

finally:

 print 'finally...'

print 'END'

Copy after login

Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。比如:

1

2

3

4

5

6

try:

 foo()

except StandardError, e:

 print 'StandardError'

except ValueError, e:

 print 'ValueError'

Copy after login

第二个except永远也捕获不到ValueError,因为ValueError是StandardError的子类,如果有,也被第一个except给捕获了。

Python所有的错误都是从BaseException类派生的,常见的错误类型和继承关系看这里:

https://docs.python.org/2/library/exceptions.html#exception-hierarchy

使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用foo(),foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理:

1

2

3

4

5

6

7

8

9

10

11

12

13

def foo(s):

 return 10 / int(s)

 

def bar(s):

 return foo(s) * 2

 

def main():

 try:

  bar('0')

 except StandardError, e:

  print 'Error!'

 finally:

  print 'finally...'

Copy after login

也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally的麻烦。
调用堆栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。来看看err.py:

1

2

3

4

5

6

7

8

9

10

11

# err.py:

def foo(s):

 return 10 / int(s)

 

def bar(s):

 return foo(s) * 2

 

def main():

 bar('0')

 

main()

Copy after login

执行,结果如下:

1

2

3

4

5

6

7

8

9

10

11

$ python err.py

Traceback (most recent call last):

 File "err.py", line 11, in <module>

 main()

 File "err.py", line 9, in main

 bar('0')

 File "err.py", line 6, in bar

 return foo(s) * 2

 File "err.py", line 3, in foo

 return 10 / int(s)

ZeroDivisionError: integer division or modulo by zero

Copy after login

出错并不可怕,可怕的是不知道哪里出错了。解读错误信息是定位错误的关键。我们从上往下可以看到整个错误的调用函数链:

错误信息第1行:

1

Traceback (most recent call last):

Copy after login

告诉我们这是错误的跟踪信息。

第2行:

1

2

File "err.py", line 11, in <module>

main()

Copy after login

调用main()出错了,在代码文件err.py的第11行代码,但原因是第9行:

1

2

File "err.py", line 9, in main

bar('0')

Copy after login

调用bar('0')出错了,在代码文件err.py的第9行代码,但原因是第6行:

1

2

File "err.py", line 6, in bar

return foo(s) * 2

Copy after login

原因是return foo(s) * 2这个语句出错了,但这还不是最终原因,继续往下看:

1

2

File "err.py", line 3, in foo

return 10 / int(s)

Copy after login

原因是return 10 / int(s)这个语句出错了,这是错误产生的源头,因为下面打印了:

ZeroDivisionError: integer division or modulo by zero

根据错误类型ZeroDivisionError,我们判断,int(s)本身并没有出错,但是int(s)返回0,在计算10 / 0时出错,至此,找到错误源头。
记录错误

如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。

Python内置的logging模块可以非常容易地记录错误信息:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

# err.py

import logging

 

def foo(s):

 return 10 / int(s)

 

def bar(s):

 return foo(s) * 2

 

def main():

 try:

  bar('0')

 except StandardError, e:

  logging.exception(e)

 

main()

print 'END'

Copy after login

同样是出错,但程序打印完错误信息后会继续执行,并正常退出:

1

2

3

4

5

6

7

8

9

10

11

$ python err.py

ERROR:root:integer division or modulo by zero

Traceback (most recent call last):

 File "err.py", line 12, in main

 bar('0')

 File "err.py", line 8, in bar

 return foo(s) * 2

 File "err.py", line 5, in foo

 return 10 / int(s)

ZeroDivisionError: integer division or modulo by zero

END

Copy after login

通过配置,logging还可以把错误记录到日志文件里,方便事后排查。
抛出错误

因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:

1

2

3

4

5

6

7

8

9

# err.py

class FooError(StandardError):

 pass

 

def foo(s):

 n = int(s)

 if n==0:

  raise FooError('invalid value: %s' % s)

 return 10 / n

Copy after login

执行,可以最后跟踪到我们自己定义的错误:

1

2

3

4

$ python err.py

Traceback (most recent call last):

 ...

__main__.FooError: invalid value: 0

Copy after login

只有在必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置的错误类型(比如ValueError,TypeError),尽量使用Python内置的错误类型。

最后,我们来看另一种错误处理的方式:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

# err.py

def foo(s):

 n = int(s)

 return 10 / n

 

def bar(s):

 try:

  return foo(s) * 2

 except StandardError, e:

  print 'Error!'

  raise

 

def main():

 bar('0')

 

main()

Copy after login

在bar()函数中,我们明明已经捕获了错误,但是,打印一个Error!后,又把错误通过raise语句抛出去了,这不有病么?

其实这种错误处理方式不但没病,而且相当常见。捕获错误目的只是记录一下,便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,所以,最恰当的方式是继续往上抛,让顶层调用者去处理。

raise语句如果不带参数,就会把当前错误原样抛出。此外,在except中raise一个Error,还可以把一种类型的错误转化成另一种类型:

1

2

3

4

try:

 10 / 0

except ZeroDivisionError:

 raise ValueError('input error!')

Copy after login

只要是合理的转换逻辑就可以,但是,决不应该把一个IOError转换成毫不相干的ValueError。
小结

Python内置的try...except...finally用来处理错误十分方便。出错时,会分析错误信息并定位错误发生的代码位置才是最关键的。

程序也可以主动抛出错误,让调用者来处理相应的错误。但是,应该在文档中写清楚可能会抛出哪些错误,以及错误产生的原因。

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Python: Games, GUIs, and More Python: Games, GUIs, and More Apr 13, 2025 am 12:14 AM

Python excels in gaming and GUI development. 1) Game development uses Pygame, providing drawing, audio and other functions, which are suitable for creating 2D games. 2) GUI development can choose Tkinter or PyQt. Tkinter is simple and easy to use, PyQt has rich functions and is suitable for professional development.

PHP and Python: Comparing Two Popular Programming Languages PHP and Python: Comparing Two Popular Programming Languages Apr 14, 2025 am 12:13 AM

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

How debian readdir integrates with other tools How debian readdir integrates with other tools Apr 13, 2025 am 09:42 AM

The readdir function in the Debian system is a system call used to read directory contents and is often used in C programming. This article will explain how to integrate readdir with other tools to enhance its functionality. Method 1: Combining C language program and pipeline First, write a C program to call the readdir function and output the result: #include#include#include#includeintmain(intargc,char*argv[]){DIR*dir;structdirent*entry;if(argc!=2){

Python and Time: Making the Most of Your Study Time Python and Time: Making the Most of Your Study Time Apr 14, 2025 am 12:02 AM

To maximize the efficiency of learning Python in a limited time, you can use Python's datetime, time, and schedule modules. 1. The datetime module is used to record and plan learning time. 2. The time module helps to set study and rest time. 3. The schedule module automatically arranges weekly learning tasks.

Nginx SSL Certificate Update Debian Tutorial Nginx SSL Certificate Update Debian Tutorial Apr 13, 2025 am 07:21 AM

This article will guide you on how to update your NginxSSL certificate on your Debian system. Step 1: Install Certbot First, make sure your system has certbot and python3-certbot-nginx packages installed. If not installed, please execute the following command: sudoapt-getupdatesudoapt-getinstallcertbotpython3-certbot-nginx Step 2: Obtain and configure the certificate Use the certbot command to obtain the Let'sEncrypt certificate and configure Nginx: sudocertbot--nginx Follow the prompts to select

How to configure HTTPS server in Debian OpenSSL How to configure HTTPS server in Debian OpenSSL Apr 13, 2025 am 11:03 AM

Configuring an HTTPS server on a Debian system involves several steps, including installing the necessary software, generating an SSL certificate, and configuring a web server (such as Apache or Nginx) to use an SSL certificate. Here is a basic guide, assuming you are using an ApacheWeb server. 1. Install the necessary software First, make sure your system is up to date and install Apache and OpenSSL: sudoaptupdatesudoaptupgradesudoaptinsta

GitLab's plug-in development guide on Debian GitLab's plug-in development guide on Debian Apr 13, 2025 am 08:24 AM

Developing a GitLab plugin on Debian requires some specific steps and knowledge. Here is a basic guide to help you get started with this process. Installing GitLab First, you need to install GitLab on your Debian system. You can refer to the official installation manual of GitLab. Get API access token Before performing API integration, you need to get GitLab's API access token first. Open the GitLab dashboard, find the "AccessTokens" option in the user settings, and generate a new access token. Will be generated

What service is apache What service is apache Apr 13, 2025 pm 12:06 PM

Apache is the hero behind the Internet. It is not only a web server, but also a powerful platform that supports huge traffic and provides dynamic content. It provides extremely high flexibility through a modular design, allowing for the expansion of various functions as needed. However, modularity also presents configuration and performance challenges that require careful management. Apache is suitable for server scenarios that require highly customizable and meet complex needs.

See all articles