Skip to content

错误处理

try...except1...[exceptN...[finally...]

1
2
3
4
5
6
try:
    可能会出现异常的代码
except 异常类型 [as 别名]
    出现异常后的处理
finally:
    不管是否出现异常最后都会执行的代码

Example

# 出现 除零的异常 示例

try:
    print("Try---------")
    r = 10/0
    print("result: ", r)
except ZeroDivisionError as e:
    print("Except------", e)
finally:
    print("Finally-----")

print("END")

--------------------------------------------------

# Output:
Try---------
Except------ division by zero
Finally-----
END

try 语句块中的代码遇到异常后会跳转到 except 语句块执行 而 finally 语句块不管有没有异常最后都会执行。当然,也可以没有 finally 语句

没有异常的示例

try:
    print("Try---------")
    r = 10/2
    print("result: ", r)
except ZeroDivisionError as e:
    print("Except------", e)
finally:
    print("Finally-----")

print("END")

--------------------------------------------------

# Output:
Try---------
result: 5
Finally-----
END

捕获多个异常

捕获异常不止可以捕获一个,还可以捕获多个

捕获多个异常

try:
    print("Try---------")
    r = 10 / int('a')
    print("result: ", r)
except ValueError as e:
    print('ValueError: ', e)
except ZeroDivisionError as e:
    print("ZeroDivisionError: ", e)
finally:
    print("Finally-----")

print("END")

--------------------------------------------------

# Output:

Try---------
ValueError:  invalid literal for int() with base 10: 'a'
Finally-----
END

else 语句

在 except 后面还可以加一个 else 语句块

# else 语句在没有异常的情况下 示例

try:
    print("Try---------")
    r = 10 / int('2')
    print("result: ", r)
except ValueError as e:
    print('ValueError: ', e)
except ZeroDivisionError as e:
    print("ZeroDivisionError: ", e)
else:
    print("Else--------No Error!")
finally:
    print("Finally-----")

print("END")

--------------------------------------------------

# Output:

Try---------
result: 5.0
Else--------No Error!
Finally-----
END
else 语句不同于finally 语句。finally 语句是有无异常都会执行,else 语句会在没有异常的情况下执行
# else 语句在有异常的情况下 示例

try:
    print("Try---------")
    r = 10 / int('a')
    print("result: ", r)
except ValueError as e:
    print('ValueError: ', e)
except ZeroDivisionError as e:
    print("ZeroDivisionError: ", e)
else:
    print("Else--------No Error!")
finally:
    print("Finally-----")

print("END")

--------------------------------------------------

# Output:
Try---------
ValueError:  invalid literal for int() with base 10: 'a'
Finally-----
END

优点:跨越多层调用

例如现在 A() 调用 B()B() 调用 C(),在 C() 出错了,只要 A() 捕获到了,就可以处理。

def C(s):
    return 10 / int(s)

def B(s):
    return C(s) * 2

def A():
    try:
        B('0')
    except Exception as e:
        print("Error:", e)
    finally:
        print("Finally------")

A()

--------------------------------------------------

# Output:

Error: division by zero
Finally------
虽然错误是在 C() 出现,但是在 A() 也能捕获。 如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。

错误是个class

所有的错误类型都继承自 BaseException,如果捕获到了一个父类错误,其子类错误不会被捕获。 例如:

1
2
3
4
5
6
try:
    foo()
except ValueError as e:
    print('ValueError')
except UnicodeError as e:
    print('UnicodeError')
第二个except永远捕获不到 UnicodeError,因为UnicodeErrorValueError的子类。

即使有UnicodeError,也被第一个except捕获了。

错误类继承关系

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration 
      +-- AttributeError     属性错误
      +-- AssertionError     断言错误
      +-- BufferError        缓冲错误
      +-- EOFError           文件结束符错误
      +-- MemoryError        内存错误
      +-- ReferenceError
      +-- SystemError        系统错误
      +-- TypeError          类型错误
      +-- ArithmeticError    算术错误
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- ImportError        导入错误
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- NameError          命名错误
      |    +-- UnboundLocalError
      +-- OSError            操作系统错误
      |    +-- BlockingIOError      IO阻塞错误
      |    +-- ChildProcessError    子进程错误
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- RuntimeError       运行时错误
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError        同步错误
      |    +-- IndentationError
      |         +-- TabError
      +-- ValueError         值错误
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning            警告
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

抛出错误

错误是 class, 捕获错误实质上就是捕获到该 class 的一个实例。因此,错误是可以有意创建并抛出的。

try...except...是承接错误,而raise是抛出错误

def register():
    username = input("请输入用户名:")
    if len(username) < 6:
        raise Exception("用户名长度必须6位以上")
    else:
        print("输入的用户名是:", username)


register()

--------------------------------------------------

# Output1:
请输入用户名admin
Traceback (most recent call last):
  File "d:/---Programming---/Python/Project/mo2.py", line 9, in <module>
    register()
  File "d:/---Programming---/Python/Project/mo2.py", line 4, in register
    raise Exception("用户名长度必须6位以上")
Exception: 用户名长度必须6位以上

# Output2:
请输入用户名administor
输入的用户名是: administor
在 if 中主动raise抛出错误,但是调用register()的地方没有try...except来捕获错误,所以最后由解释器处理,打印出了错误信息

def register():
    username = input("请输入用户名:")
    if len(username) < 6:
        raise Exception("用户名长度必须6位以上")
    else:
        print("输入的用户名是:", username)

try:
    register()
except Exception as e:
    print(e)
    print("注册失败")
else:
    print("注册成功")

--------------------------------------------------

# Output1:
请输入用户名admin
用户名长度必须6位以上
注册失败

# Output2:
请输入用户名administor
输入的用户名是: administor
注册成功
在 if 处 raise抛出错误,在register()使用了try...except捕获错误,然后进行了处理。

自定义错误

主动抛出错误,这个错误可以是自己定义的 class,因为错误也是 class。

class NameUndercutting(Exception):
    pass

def register():
    username = input("请输入用户名:")
    if len(username) < 6:
        raise Exception("用户名长度必须6位以上")
    else:
        print("输入的用户名是:", username)

try:
    register()
except NameUndercutting as e:
    print(e)
    print("注册失败")
else:
    print("注册成功")

--------------------------------------------------

# Output1:
请输入用户名admin
用户名长度必须6位以上
注册失败

# Output2:
请输入用户名administor
输入的用户名是: administor
注册成功