目录
一、异常的类型
1.NameError
2.SyntaxError
3.TypeError
4.ValueError
5.IndexError
6.KeyError
二、异常处理
1.try/except语句的基本结构
2.捕获异常的描述信息
3.finally语句与终止行为
三、主动触发异常
1.raise语句
2.assert语句
四、第十七课函数基础练习答案
1.函数基础练习
2.寻找回文数
3.用户注册登陆系统
异常指程序在运行时发生的错误。如果没有提前对可能出现的错误设置处理过程,程序将自动停止。
异常处理主要指的是对异常的捕获、处理及引发异常。
异常在python中是一种对象,对应不同原因引起的错误有不同的错误类型。
一旦某段代码程序无法处理时,就会引发异常。如下:输出一个未曾定义过的变量a时,会引发异常。此时,计算机会自动输出异常信息,从而提示程序员代码哪里发生了何种错误。
下面我们来看一些常见的异常类型。
未找到本地或全局变量,即在访问一个未声明的变量。异常信息中包含未定义的变量名称。
print(a)
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 1, in
print(a)
NameError: name 'a' is not defined
语法错误也很常见。如在if语句后面漏写了冒号。
if 3>5
print(3)
else:
print(5)
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 1
if 3>5
^
SyntaxError: invalid syntax
类型错误。用户将某些操作应用在不合适的类型对象时,将引发此类错误。例如通过索引方法修改字符串中的某个值就属于类型错误。
name = 'der'
name[0] = 'e'
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 2, in
name[0] = 'e'
TypeError: 'str' object does not support item assignment
值错误。当操作或函数接收到类型正确但值不合适的参数时引发。
n = 'k'
print(int(n))
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 2, in
print(int(n))
ValueError: invalid literal for int() with base 10: 'k'
索引错误。当使用序列中不存在的索引时引发。
lst = [1,2]
print(lst[2])
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 2, in
print(lst[2])
IndexError: list index out of range
键错误。当使用映射中不存在的键时引发。
mydict = {1:'a',2:'b'}
print(mydict[3])
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 2, in
print(mydict[3])
KeyError: 3
当你不想在异常发生时结束你的程序,可以使用try/except语句来捕捉并处理异常情况。
try/except语句用以检测try语句块中是否存在错误,从而让except语句捕捉异常并处理它。
处理任意异常
try:
<语句块> # 需要监测的代码
except: # try中发生错误就执行该except中的语句块
<语句块> #
处理指定异常
try:
<语句块> # 需要监测的代码
except <异常名称1>:
<语句块> # 发生异常名称1时的处理代码
except <异常名称2 as result>: # result用于接收异常处理信息
<语句> # 输出异常信息、处理异常
else:
<语句> # 如果没有异常发生将要执行的语句
在处理任意异常时,先执行try中的语句块,如果某行代码发生异常,将不再执行后面的语句,而是执行except中的语句块,然后执行try语句后面的代码。
try:
print(a)
except:
print(1)
# 输出
1
在处理指定异常时,先执行try中的语句块,如果某行代码发生异常,将执行第一个匹配该异常的except的子句,然后执行try语句后面的代码。
try:
print(a)
except ValueError:
print(1)
except NameError:
print(2)
# 输出
2
一个except中也可以设定多个异常,将他们放在元组中。
try:
lst = [1,2,3,4]
print(lst.keys())
except (ValueError,NameError):
print(1)
except (KeyError,IndexError):
print(2)
except (TypeError,AttributeError):
print(3)
# 输出
3 # 错误的原因是列表没有keys方法
在except中使用as关键字,用变量来接收异常信息。
try:
lst = [1,2,3,4]
print(lst.keys())
except (ValueError,NameError) as result:
print(1)
print(result)
except (KeyError,IndexError) as result:
print(2)
print(result)
except (TypeError,AttributeError) as result:
print(3)
print(result)
# 输出
3
'list' object has no attribute 'keys'
执行时先运行try中的语句块,如果发生异常,将执行第一次匹配该异常的except语句,同时将异常信息存储到变量result中。
在python中BaseException是所有异常的基类,如果通过使用BaseException来捕获任意异常,就不用预先知道将要发生何种异常。
try:
lst = [1,2,3,4]
print(lst.keys())
except BaseException as result:
print(1)
print(result)
# 输出
1
'list' object has no attribute 'keys'
try语句完整结构是try-except-else-finally。在try语句执行过程中如果没有发生任何异常,则程序在执行完try语句块后会进入else语句块执行;finally语句中是无论是否发生异常都将执行finally中的语句。
try:
int('a')
except Exception as result:
print(1)
print(result)
else:
print(2)
finally:
print('try is end')
# 输出
1
invalid literal for int() with base 10: 'a'
try is end
注意:else和finally语句都是可选的,且finally语句必须在整个结构的末尾。else语句不能与没有except语句的异常处理结构配合使用,不然会引发语法错误。
在程序中,有一种情况是,无论是否捕捉到异常,都要执行一些终止行为,比如关闭文件、释放锁等,这时可以使用finally语句进行处理。
try:
file = open('test.txt','r+')
while True:
content = file.read()
if len(content) == 0:
break
print(content)
finally:
file.close()
print('关闭文件')
# 输出
This is a test file.
关闭文件
在try语句中使用读写方法open打开一个已经存在名为“test”的txt文件,接着在while语句中读取文档中的内容存到content中,如果content中有内容则输出它,最后在finally中使用close方法关闭文件。
通常来说当程序发生错误时会触发异常,除此以外,有时我们会需要主动触发异常。例如:当值小于0时,触发ValueError。
number = -1
if number < 0:
raise ValueError
# 输出
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 3, in
raise ValueError
ValueError
对异常添加描述信息。
number = -1
if number < 0:
raise ValueError('值小于0')
# 输出
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 3, in
raise ValueError('值小于0')
ValueError: 值小于0
使用不带参数的raise可以再次引发异常。常用需要对异常信息进一步判断,如果满足某种条件,则触发异常,否则做其他处理。
当n值小于0时抛出异常,如果n的值为-2,则打印n的绝对值,否则引发异常。
n = -3
try:
if n < 0:
raise ValueError('值小于0,且不等于-2')
else:
print(n)
except Exception as result:
if n == -2:
print(abs(n))
else:
raise
# 输出
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 4, in
raise ValueError('值小于0,且不等于-2')
ValueError: 值小于0,且不等于-2
异常引发异常。如果要在异常中抛出另一个异常,可以使用raise-from语句。
try:
num
except Exception as result:
raise IndexError('下标超出范围') from result
# 输出
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 2, in
num
NameError: name 'num' is not defined
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/binhu/PycharmProjects/learnpython/temp.py", line 4, in
raise IndexError('下标超出范围') from result
IndexError: 下标超出范围
assert语句又称为断言,指的是期望用户满足指定的条件。当用户定义的约束条件不满足的时候,它会触发AssertionError异常,所以assert语句可以当作条件式的raise语句。
assert语句的格式为:
assert 逻辑表达式,data # data为可选,通常为字符串
等效于:
if not 逻辑表达式:
raise AssertionError(data)
示例:
程序中a=0,第三行断言a的值必须大于等于1,抛出异常,异常信息为"a的值不能小于1"。except语句将异常信息传递给result,第五行输出异常信息。
a= 0
try:
assert a>=1,"a的值不能小于1"
except Exception as result:
print(result)
# 输出
a的值不能小于1
注:自定义异常在后续“对象”章节中进行讲解。
# 任务1:lst中有[1,2,3,4,5,6,7,8,9],定义一个名为add_odd()的函数,参数为x用以接收lst,在函数中将所有奇数存到一个新的列表中,返回给调用函数,并计算输出新列表的和。
# 在此处下方定义add_odd()
def add_odd(x):
odd_lst = []
for i in x:
if i % 2 != 0:
odd_lst.append(i)
return odd_lst
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_lst = add_odd(lst)
print(odd_lst)
# 在此处次方编写函数调用语句
# 任务2:写一个函数,判断用户传入的对象长度是否大于5
def getlen(x):
return len(x) > 5
result = getlen(input("请用户输入任意内容:"))
print(result)
# 任务3:编写函数,求“1/(1*2)-1/(2*3)+1/(3*4)-1/(4*5)+……”前n项的和,将n作为参数,n由用户输入。
def func(n):
sum = 0
for i in range(1,n+1):
if i % 2 == 0:
sum -= 1/(i*(i+1))
else:
sum += 1/(i*(i+1))
return sum
summary = func(int(input("请用户输入任意整数:")))
print(summary)
# 回文数是一个正向和逆向都相同的数,如12321、7887等,请编写函数找出1到n之间的所有回文数,并将其存入列表中打印出来。将n作为参数,n由用户输入。
def func(n):
lst = []
for i in range(n+1):
if str(i) == str(i)[::-1]:
lst.append(i)
return lst
print(func(int(input("请输入任意整数"))))
# 子任务1: 创建一个名为displaymenu的函数,展示如下图所示的系统菜单。
# ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
# 用户注册登陆系统
# 1用户注册
# 2用户登陆
# 3退出系统
# ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
def displaymenu():
print("*" * 30)
print("User Login System".center(30))
lst = ["用户注册", "用户登陆", "退出系统"]
for i in range(len(lst)):
print(i + 1, lst[i])
print("*" * 30)
# 子任务2: 创建一个名为getchoice的函数,提示“请选择您想要操作的序号”。要求对用户输入序号的正确性进行判断,如果序号正确,则返回该序号的整形。
def getchoice():
userinput = input("请选择您想要操作的序号")
if userinput.isdigit():
userinput = int(userinput)
if userinput in range(1, 4):
return userinput
else:
print("序号不在范围内,请重新输入")
getchoice()
else:
print("请输入正确的序号")
getchoice()
# 子任务3: 创建一个名为user_register的函数,提示用户依次输入用户名、密码、确认密码,并对以上信息按以下规则依次进行检查:
# (1)用户名不重复,且以字母开头、用户名长度在6到30位之间,可包含字母、数字和下划线,以小写保存。
# (2)密码不得少于6位,包含字母、数字和下划线其中至少2种。
# (3)确认密码与输入密码必须一致。
# (4)注册成功时提示用户已成功注册。
# 其他要求:检验发现格式错误的,应给予用户错误提示,直到用户注册成功才退回到系统菜单页面。用户名和密码以
# {username: (username, password)}
# 键值对的形式存储在名为userinfo的字典中。
def user_register():
username = ""
def get_username():
nonlocal username
username = input("请输入用户名'由字母、数字、下划线组成,长度不少于6个字符':")
if 6 > len(username) > 30:
print("长度不足6个字符")
get_username()
else:
yesorno = True
for i in username:
if 'a' <= i <= 'z' or i >= 'A' and i <= 'A' or ord(str(i)) >= 48 and ord(
str(i)) <= 57 or i == '_':
continue
else:
yesorno = False
if yesorno:
if username in userinfo.keys():
print("用户名已存在")
get_username()
else:
print("用户名中包含非法字符")
get_username()
def get_password():
password = input("请输入密码'由字母、数字、下划线至少两种组成,长度不少于6个字符':")
if len(password) < 6:
print("长度不足6")
get_password()
else:
if password[0].isalpha() or password[0] == '_': # 判断第一个字符是否字母、下划线
if not password.isalpha() and not password.isdigit(): # 判断密码是否全部为数字或字母
check_password = input("请再次输入密码:")
if password == check_password:
userinfo[username] = (username, password)
else:
print("密码不一致")
get_password()
else:
print("密码应至少包含数字、字母或下划线中的两种")
get_password()
else:
print("首字母不得为数字")
get_password()
get_username()
get_password()
# 子任务4: 创建一个名为user_logo的函数,提示用户依次输入用户名、密码,并对以上信息按以下规则依次进行验证:
# (1)检查用户名是否已存在于userinfo中,如果不存在,则提示该用户名不存在。
# (2)继续判断用户名匹配的密码是否一直,如果不匹配则提示密码错误。
# (3)登陆成功时提示用户成功登陆。
def user_logo():
username = input("请输入用户名")
password = input("请输入密码")
if username not in userinfo.keys():
print("用户名不存在")
else:
if password != userinfo[username][1]:
print("用户名或密码错误")
else:
print("恭喜你,登陆成功!")
# 子任务5: 主程序
# (1)调用displaymenu函数
# (2)调用getchoice函数并获得用户的输入
# (3)根据用户的输入分别匹配调用user_register、user_logo函数,如果用户输入3,则退出本程序。
userinfo = {}
while True:
displaymenu()
choice = getchoice()
if choice == 1:
user_register()
elif choice == 2:
user_logo()
elif choice == 3:
exit()