在python中,一个错误可以分为两种:语法错误和异常。语法错误是指你的代码写得不符合python的规则,比如少了一个冒号或者括号不匹配。这种错误通常会在你运行程序之前就被发现,并且会提示你在哪一行出错了。
一,语法错误:
比如,如果你写了这样的代码:
# 定义一个函数
def print_hello()
print("Hello, world!")
你会看到这样的错误信息:
File "<stdin>", line 1
def print_hello()
^
SyntaxError: invalid syntax
这个错误信息告诉你,在第一行的最后,你少了一个冒号(:),这是一个语法错误。要修复这个错误,你只需要在函数名后面加上一个冒号就可以了。
二,异常:try…except…finally
异常是指你的代码写得符合python的规则,但是在执行时遇到了一些问题,比如除以零或者访问不存在的变量。这种错误通常会在你运行程序时才被发现,并且会提示你发生了什么异常以及在哪里发生了异常。比如,如果你写了这样的代码:
# 定义一个变量
x = 10
# 尝试用x除以0
y = x / 0
你会看到这样的错误信息:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
ZeroDivisionError: division by zero
这个错误信息告诉你,在第三行,你尝试用x除以0,这是一个除零错误(ZeroDivisionError),也就是一个异常。要修复这个错误,你需要避免用任何数除以0,或者用其他方式处理这个异常。
要处理异常,你可以使用try…except…finally语句。这个语句可以让你测试一段代码是否会发生异常,并且根据不同的异常类型来执行不同的操作(用try expect,处理多种错误的方法是在try语句后面跟上多个except语句,每个except语句指定一个或多个异常类型,并且可以执行相应的操作)。最后,如果没有发生任何异常,就会跳过所有的except语句。最后finally语句会被执行。你可以这样写代码:
# 尝试执行一段代码
try:
# 定义两个变量
x = 10
y = "a"
# 尝试用x除以y
z = x / y
# 如果发生除零错误,执行以下操作
except ZeroDivisionError:
# 打印一条提示信息
print("You can't divide by zero!")
# 如果发生类型错误,执行以下操作
except TypeError:
# 打印一条提示信息
print("You can't divide by different types!")
# 如果发生值错误,执行以下操作
except ValueError:
# 打印一条提示信息
print("You can't divide by an invalid value!")
# 如果发生其他类型的错误,执行以下操作
except Exception as e:
# 打印出错的类型和信息
print(f"An error occurred: {type(e)}: {e}")
# 无论是否发生错误,都执行以下操作
finally:
# 打印一条结束信息
print("The program is finished.")
你会看到这样的输出:
You can't divide by zero!
The program is finished.
这个输出告诉你,在try语句中,发生了一个除零错误(ZeroDivisionError),所以except ZeroDivisionError语句被执行,并打印出了一条提示信息。然后finally语句被执行,并打印出了一条结束信息。
如果你把代码中的y = x / 0改成y = x / z,你会看到这样的输出:
An error occurred: <class 'NameError'>: name 'z' is not defined
The program is finished.
这个输出告诉你,在try语句中,发生了一个名字错误(NameError),因为变量z没有被定义。所以except Exception as e语句被执行,并打印出了出错的类型和信息。然后finally语句被执行,并打印出了一条结束信息。
如果你把代码中的y = x / 0改成y = x / 2,你会看到这样的输出:
The program is finished.
这个输出告诉你,在try语句中,没有发生任何错误,所以except语句都没有被执行。只有finally语句被执行,并打印出了一条结束信息。
三,自定义异常类型
要定义自己的异常类型,你可以创建一个新的类,这个类继承自内置的Exception类或者它的子类之一。比如,如果你想定义一个表示温度范围错误的异常类型,你可以这样写:
# 定义一个温度范围错误类,它继承自ValueError类
class TemperatureRangeError(ValueError):
# 定义一个初始化方法,接受温度值和信息作为参数
def __init__(self, temperature, message):
# 调用父类的初始化方法
super().__init__(message)
# 保存温度值作为属性
self.temperature = temperature
这样,你就定义了一个自己的异常类型TemperatureRangeError,它继承自ValueError类,并且接受温度值和信息作为参数。要抛出这个异常,你可以使用raise语句:
# 定义一个函数,用来检查温度是否在合理范围内
def check_temperature(temperature):
# 如果温度小于-273.15摄氏度或者大于100摄氏度
if temperature < -273.15 or temperature > 100:
# 抛出温度范围错误异常,并传入温度值和信息
raise TemperatureRangeError(temperature, "Temperature is out of range")
# 调用函数,并传入一个不合理的温度值
check_temperature(-300)
这样,当你调用函数时,就会抛出温度范围错误异常,并显示以下信息:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in check_temperature
__main__.TemperatureRangeError: Temperature is out of range
要捕获这个异常,你可以使用try…except语句:
# 尝试执行一段代码
try:
# 调用函数,并传入一个不合理的温度值
check_temperature(-300)
# 如果捕获到温度范围错误异常,并把异常对象存储到变量e中
except TemperatureRangeError as e:
# 打印出错的温度值和信息(通过e.temperature来访问异常对象的温度属性,或者通过str(e)来获取异常对象的信息字符串,并打印出来。)
print(f"The temperature {e.temperature} is out of range: {e}")
这样,当你执行try语句时,就会捕获到温度范围错误异常,并打印以下信息:
The temperature -300 is out of range: Temperature is out of range
四,Raise语句的用法
raise语句是一种用来抛出异常的语法,它可以让你在程序中主动触发一个错误或者提示一个问题。raise语句有以下几种用法:
- raise <异常类型>:这种用法可以抛出一个指定类型的异常,比如raise ZeroDivisionError或者raise ValueError。你可以选择使用python内置的异常类型,或者自定义的异常类型。
# 定义一个函数,用来计算两个数的商
def divide(a, b):
# 如果除数是0
if b == 0:
# 抛出一个除零错误异常
raise ZeroDivisionError("You can't divide by zero!")
# 否则,返回两个数的商
return a / b
# 调用函数,并传入两个数
print(divide(10, 2)) # 输出 5.0
print(divide(10, 0)) # 抛出 ZeroDivisionError: You can't divide by zero!
- raise <异常类型>(<信息>):这种用法可以抛出一个指定类型的异常,并且附加一些信息,比如raise ZeroDivisionError(“You can’t divide by zero!”)或者raise ValueError(“Invalid input”).这些信息可以帮助你或者用户更好地理解发生了什么问题。
# 定义一个函数,用来检查输入是否是整数
def check_input(input):
# 尝试把输入转换成整数
try:
x = int(input)
# 如果发生类型错误异常
except TypeError:
# 抛出一个值错误异常,并附加信息
raise ValueError("Invalid input: expected an integer") from TypeError("Expected an integer")
# 调用函数,并传入一个输入
check_input("abc") # 抛出 ValueError: Invalid input: expected an integer
- raise <异常对象>:这种用法可以抛出一个已经创建好的异常对象,比如ex = ZeroDivisionError(“You can’t divide by zero!”),然后raise ex。这样可以让你在抛出异常之前对异常对象进行一些操作或修改。
# 定义一个函数,用来计算两个数的商
def divide(a, b):
# 如果除数是0
if b == 0:
# 创建一个除零错误异常对象,并保存到变量ex中
ex = ZeroDivisionError("You can't divide by zero!")
# 给异常对象添加一个属性,表示被除数的值
ex.dividend = a
# 抛出异常对象
raise ex
# 否则,返回两个数的商
return a / b
# 尝试执行一段代码
try:
# 调用函数,并传入两个数
print(divide(10, 0))
# 如果捕获到除零错误异常,并把异常对象存储到变量e中
except ZeroDivisionError as e:
# 打印出错的信息和被除数的值
print(f"{e}: the dividend is {e.dividend}") # 输出 You can't divide by zero!: the dividend is 10
- raise:这种用法可以重新抛出之前捕获到的异常,比如在try…except语句中,如果你想在处理完异常后再次抛出它,你可以在except语句中使用raise。
# 定义一个函数,用来计算两个数的商
def divide(a, b):
# 如果除数是0
if b == 0:
# 抛出一个除零错误异常
raise ZeroDivisionError("You can't divide by zero!")
# 否则,返回两个数的商
return a / b
# 尝试执行一段代码
try:
# 调用函数,并传入两个数
print(divide(10, 0))
# 如果捕获到除零错误异常,并把异常对象存储到变量e中
except ZeroDivisionError as e:
# 打印出错的信息
print(f"An error occurred: {e}")
# 重新抛出捕获到的异常
raise
- raise <异常类型> from <原因>:这种用法可以抛出一个指定类型的异常,并且指明导致这个异常的原因,比如raise ValueError(“Invalid input”) from TypeError(“Expected an integer”).这样可以让你创建一个异常链,显示出错误的来源和传播。
# 定义一个函数,用来检查输入是否是整数
def check_input(input):
# 尝试把输入转换成整数
try:
x = int(input)
# 如果发生类型错误异常
except TypeError:
# 抛出一个值错误异常,并指明原因
raise ValueError("Invalid input: expected an integer") from TypeError("Expected an integer")
# 调用函数,并传入一个输入
check_input("abc") # 抛出 ValueError: Invalid input: expected an integer
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in check_input
TypeError: Expected an integer