【一】什么是异常
- 异常是程序运行时可能发生的错误或意外情况。在Python中,异常是一种对象,表示程序执行期间发生的错误。
- 当出现异常时,程序的正常流程会被中断,而是跳转到异常处理流程。
【二】异常分类
- 在Python中,异常分为两类:
- 内建异常(Built-in Exceptions):由Python内部定义的异常,例如
ZeroDivisionError
、NameError
等。 - 用户自定义异常:由程序员自己定义的异常,用于满足特定的业务需求。
- 内建异常(Built-in Exceptions):由Python内部定义的异常,例如
【1】BaseException(所有异常的基类)
- SystemExit:解释器请求退出
- KeyboardInterrupt:用户中断执行(通常是输入^C)
- Exception:常规错误的基类
- StopIteration:迭代器没有更多的值
- GeneratorExit:生成器(generator)发生异常来通知退出
- StandardError:所有的内建标准异常的基类
- ArithmeticError:所有数值计算错误的基类
- FloatingPointError:浮点计算错误
- OverflowError:数值运算超出最大限制
- ZeroDivisionError:除(或取模)零 (所有数据类型)
- AssertionError:断言语句失败
- AttributeError:对象没有这个属性
- EOFError:没有内建输入,到达EOF 标记
- EnvironmentError:操作系统错误的基类
- IOError:输入/输出操作失败
- OSError:操作系统错误
- WindowsError:系统调用失败
- ImportError:导入模块/对象失败
- LookupError:无效数据查询的基类
- IndexError:序列中没有此索引(index)
- KeyError:映射中没有这个键
- MemoryError:内存溢出错误(对于Python 解释器不是致命的)
- NameError:未声明/初始化对象 (没有属性)
- UnboundLocalError:访问未初始化的本地变量
- ReferenceError:弱引用(Weak reference)试图访问已经垃圾回收了的对象
- RuntimeError:一般的运行时错误
- NotImplementedError:尚未实现的方法
- SyntaxError:Python 语法错误
- IndentationError:缩进错误
- TabError:Tab 和空格混用
- SystemError:一般的解释器系统错误
- TypeError:对类型无效的操作
- ValueError:传入无效的参数
- UnicodeError:Unicode 相关的错误
- UnicodeDecodeError:Unicode 解码时的错误
- UnicodeEncodeError:Unicode 编码时错误
- UnicodeTranslateError:Unicode 转换时错误
【2】warning(警告的基类)
- DeprecationWarning:关于被弃用的特征的警告
- FutureWarning:关于构造将来语义会有改变的警告
- OverflowWarning:旧的关于自动提升为长整型(long)的警告
- PendingDeprecationWarning:关于特性将会被废弃的警告
- RuntimeWarning:可疑的运行时行为(runtime behavior)的警告
- SyntaxWarning:可疑的语法的警告
- UserWarning:用户代码生成的警告
【三】触发异常
- 我们可以使用raise语句自己触发异常
raise [Exception [, args [, traceback]]]
-
语句中 Exception 是异常的类型
- (例如,NameError)参数标准异常中任一种,args 是自已提供的异常参数。
- 最后一个参数是可选的(在实践中很少使用),如果存在,是跟踪异常对象。
-
一个异常可以是一个字符串,类或对象。
- Python的内核提供的异常,大多数都是实例化的类,这是一个类的实例的参数。
- 定义一个异常非常简单,如下所示:
def functionName( level ):
if level < 1:
raise Exception("Invalid level!", level)
# 触发异常后,后面的代码就不会再执行
- 为了能够捕获异常
- "except"语句必须有用相同的异常来抛出类对象或者字符串。
- 例如我们捕获以上异常
- "except"语句如下所示
try:
正常逻辑
except Exception,err:
触发自定义异常
else:
其余代码
【四】异常处理
- 捕捉异常可以使用try/except语句。
- try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。
- 如果你不想在异常发生时结束你的程序,只需在try里捕获它。
- try的工作原理是,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。
- 如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)。
- 如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印默认的出错信息)。
- 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。
【1】异常捕获语法
[1]语法
try:
# 正常可能会触发异常的代码
except ExceptionType as e:
# 触发异常后执行的代码
[2]示例
try:
name = "Dream"
name[0] = 'd'
except Exception as e:
print(f"触发异常 :>>>> {e}")
# 触发异常 :>>>> 'str' object does not support item assignment
[3]分析
- 字符串不允许索引取值修改值,因此会报错
- 报错后被except语句捕获到,并将异常信息打印出来
【2】不带任何异常类型使用except
[1]语法
try:
# 正常的操作
...
except:
# 发生异常,执行这块代码
...
[2]示例
try:
result = 10 / 0
except:
print("An error occurred")
# An error occurred
[3]分析
- 在实际代码中不建议使用不带任何异常类型的
except
语句,因为它会捕获所有异常,包括程序中可能不期望捕获的异常,使得排查问题变得困难。
【3】异常分支语法
[1]语法
try:
# 正常的操作
...
except:
# 发生异常,执行这块代码
...
else:
# 如果没有异常执行这块代码
...
[2]示例
try:
age = int(input("请输入你的年龄: "))
except ValueError:
print("Invalid input! Please enter a valid integer.")
else:
print(f"You entered: {age}")
[3]分析
- 异常分支语法中的
else
块中的代码在没有异常发生时执行,它提供了一种清晰的逻辑结构,可以更好地组织代码。
【4】使用相同的except语句来处理多个异常信息
[1]语法
try:
# 正常的操作
...
except(Exception1[, Exception2[, ...ExceptionN]]]):
# 发生以上多个异常中的一个,执行这块代码
...
else:
# 如果没有异常执行这块代码
...
[2]示例
try:
result = 10 / 0
except (ZeroDivisionError, TypeError) as e:
print(f"Error: {e}")
else:
print("No exception occurred")
[3]分析
- 通过使用相同的except语句处理多个异常,可以简化代码并提高可读性。
- 多个异常类型可以放在一个元组中,用括号括起来
【5】无论是否发生异常都将执行最后的代码
[1]语法
try:
# 正常执行的代码
...
except:
# 发生异常,执行这块代码
finally:
#退出try时总会执行
...
[2]示例
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
finally:
print("Finally block is executed")
[3]分析
finally
块中的代码无论是否发生异常都将被执行,常用于资源的释放、清理等操作
【五】列表字典推导式
【1】语法
- 列表推导式可以利用列表,元组,字典,集合等数据类型,快速的生成一个特定需要的列表。
- 语法格式如下
[表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]]
【2】列表推导式
number_list = []
for i in range(5):
number_list.append(i)
print(number_list) # [0, 1, 2, 3, 4]
number_list = [i for i in range(5)]
print(number_list) # [0, 1, 2, 3, 4]
test = [1, 2, 3]
print([i * i for i in test])
# [1,4,9]
print([[i, i + 2] for i in test])
# [[1,3],[2,4],[3,5]]
# 原始列表 : 每个元素都有空格
some_animals = [' dog', 'cat ', ' sheep ']
# 列表生成式: 新的列表,每个元素都去除掉了空格
some_animals_new = [i.strip() for i in some_animals]
print(some_animals_new)
# ['dog','cat','sheep']
test_1 = [1, 2, 3]
test_2 = [4, 5, 6]
# 列表生成式 : 遍历两个列表并取出每一个列表的元素 做乘法运算
list_one = [x * y for x in test_1 for y in test_2]
print(list_one)
# [4,5,6,8,10,12,12,15,18]
# 列表生成式 : 遍历两个列表并取出每一个列表的元素 做新列表的生成
list_two = [[x, x + y] for x in test_1 for y in test_2]
print(list_two)
# [[1, 5], [1, 6], [1, 7], [2, 6], [2, 7], [2, 8], [3, 7], [3, 8], [3, 9]]
### 注意通过这两个print体会谁是内层循环,谁是外层循环
# 列表生成式 : 遍历两个列表并取出每一个列表对应索引的元素 做乘法运算
list_three = [test_1[i] * test_2[i] for i in range(len(test_1))] #len(test_1) = 3
print(list_three)
# [4, 10, 18]
# 列表生成式 : 遍历两个列表并取出每一个列表对应索引的元素 做乘法运算
list_four = [x * y for x, y in zip(test_1, test_2)]
print(list_four)
# [4, 10, 18]
test = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
list_new = [[row[i] for row in test] for i in range(len(test[0]))] # len(test[0]) = 4
print(list_new)
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
test = [1, 2, 3, 4, 5, 6]
list_one = [x for x in test if x % 2 == 0]
print(list_one)
# [2, 4, 6]
list_two = list(filter(lambda x: x % 2 == 0, test))
print(list_two)
# [2, 4, 6]
【3】字典推导式
# user_data_dict = {}
# with open('user_data.text','r',encoding='utf8') as fp:
# for line in fp:
# username,password = line.strip().split('|')
# user_data_dict[username] = password
# print(user_data_dict)
# with open('user_data.text', 'r', encoding='utf8') as fp:
# user_data_dict = {line.strip().split('|')[0]: line.strip().split('|')[1] for line in fp}
# print(user_data_dict)
【4】元组生成式
# ----> 先别管 生成的是生成器对象 后边学
# num_tuple = (i for i in range(10))
# # ---> (0,9)
# print(tuple(num_tuple))
【5】集合推导式
# 类似 列表推导式
# set_num = {i for i in range(10)}
# print(set_num)
练习
# 【全局异常捕获】
# 在指定位置添加异常捕获机制
# 如果遇到异常和报错要捕获异常信息并做定制化输出
# 【总需求】
# 【1】打印功能菜单供用户选择
# 【2】校验功能ID是否存在并且符合数字格式
# 【3】根据指定功能ID进入到指定的功能中
# 【注册功能】
# 【1】用户输入用户名和密码
# 【2】校验用户名是否存在,如果已经存在则禁止注册,否则允许注册
# 【3】使用文本文件作为数据存储位置
# 【4】用户注册时指定默认锁定状态为未锁定
# 【登录功能】
# 【1】用户输入用户名和密码
# 【2】校验用户名是否存在,如果不存在则提示注册
# 【3】校验用户状态是否是锁定状态,如果锁定不允许登录并提示管理员解除
# 【4】未锁定用户允许重试输入密码,最大重试次数为3次并提示剩余尝试次数
# 【5】用户输入密码错误次数达最大尝试次数后修改默认锁定状态为锁定
# 【文件拷贝功能】
# 【1】用户登录成功后允许使用文件拷贝程序
# 【2】用户输入指定的路径(源文件)
# (1)打开文件 (文本文件w 二进制是wb)
# (2)对文件类型做区分
# 【3】用户输入指定的路径(新文件)
# (1)复制当前文件到新位置
# (2)按照指定文件类型赋值新文件(可重命名或者使用原本的文件名)
# 【一】定制功能菜单
func_menu = '''
########################## 功能菜单 ##########################
1.注册
2.登录
3.文件拷贝
3.退出(q)
'''
# 创建全局的用户信息字典
user_data_dict = {}
login_user_data = {
'username': 'dream',
'is_locked': False,
}
# 【二】功能书写
while True:
# 【1】打印功能菜单 ---> 让人家知道有什么功能
print(func_menu)
# 【2】让人家输入功能ID做校验
func_id = input("请输入功能ID :>>>> ").strip()
if func_id == 'q':
print(f"欢迎下次光临!")
break
# (1)校验是否是数字类型
if not func_id.isdigit():
print(f"当前ID不是数字!")
continue
# (2)强制类型转换 ---字符串 --> 数字
try:
func_id = int(func_id)
except Exception as e:
print(f"当前ID不合法!")
continue
# (3)判断当前ID在我的功能菜单中
if func_id not in [1, 2, 3]:
print(f"当前功能ID不存在!")
continue
# 【3】映射视图函数 ---》 根据指定ID进入到指定功能中
# 【4】在进入视图函数之前 ---> 先将所有用户数据读取出来 ---> 存放到指定的字典中
try:
with open('user_data.txt', 'r', encoding='utf8') as fp:
# 得到的是一个列表 ---> 列表中的每一个元素存的数每一行额数据 包括换行符
# 方式一:
for line in fp:
# ['dream', '521', '0']
username, password, lock = line.strip().split(':')
user_data_dict[username] = {
'username': username,
# 0 ---> False
# 数字 0 是假的
# 但是你现在是字符串 0
'password': password,
'is_locked': bool(int(lock))
}
except Exception as e:
pass
if func_id == 1:
print(f"欢迎来到注册功能!")
# 【1】输入用户名和密码
username_input = input("请输入用户名 :>>>> ").strip()
password_input = input("请输入密 码 :>>>> ").strip()
# 【2】校验当前用户是否存在
user_data = user_data_dict.get(username_input)
if user_data:
print(f"当前用户 :>>>> {username_input} 已经注册过!")
continue
# 【3】用户不存在则新建用户信息
# 用户名:密码:锁定状态(默认是不锁定)
user_data_str = username_input + ":" + password_input + ':' + '0'
# 【4】写入用户数据
with open('user_data.txt', 'a', encoding='utf-8') as fp:
# 【5】写数据的时候注意 --->
# 每一条用户数据都是一行而不是拼在一行
fp.write(user_data_str + '\n')
print(f"当前用户 :>>>> {username_input} 注册成功!")
elif func_id == 2:
print(f"欢迎来到登录功能!")
if not user_data_dict:
print(f"当前系统无用户注册!请先注册!")
continue
# 【1】输入用户名和密码
username_input = input("请输入用户名 :>>>> ").strip()
password_input = input("请输入密 码 :>>>> ").strip()
# 【2】从当前的数据字典中获取到当前用户对象
user_data = user_data_dict.get(username_input)
if not user_data:
print(f"当前用户 {username_input} 未注册!")
continue
# 【3】注册成功并且存在 ---> 校验当前用户的锁定状态
# 正常没锁定是 false
if user_data.get('is_locked'):
print(f"当前用户已被锁定,请联系管理员解除!")
continue
# 【4】校验密码是否正确
# 声明尝试次数和最大尝试次数
count = 0
max_retry = 3
# 进入重试环节
while count <= max_retry:
count += 1
# 第一次进来校验用户名和密码书否正确 ---> 如果正确应该直接断掉
if password_input == user_data.get('password'):
login_user_data['username'] = username_input
login_user_data['is_locked'] = False
print(f"当前用户 :>>>> {username_input} 登陆成功!")
break
if count == 3:
# 尝试次数最大为3的时候进行锁定
user_data_list = []
with open('user_data.txt', 'r+', encoding='utf8') as fp:
# 得到的是一个列表 ---> 列表中的每一个元素存的数每一行额数据 包括换行符
for line in fp:
# line : dream:521:0\n
# ['dream', '521', '0']
username, password, lock = line.strip().split(':')
if username == username_input:
lock = '1'
# [username, password, lock] : ['dream', '521', '1']
# ':'.join([]) ---> dream:521:1
user_data_list.append([':'.join([username, password, lock]), '\n'])
# [['dream:521:1', '\n'], ['opp:666:0', '\n']]
fp.seek(0, 0)
for item in user_data_list:
# item : ['dream:521:1', '\n']
# dream:521:1\n
fp.writelines(item)
print(f"当前用户密码尝试次数已达到最高,用户锁定,请联系管理员解除!")
break
print(f"当前用户密码错误")
print(f"当前用户尝试次数还有 {max_retry - count} 次! ")
password_input = input("请输入密 码 :>>>> ").strip()
continue
elif func_id == 3:
print(f"欢迎来到当前文件拷贝功能")
# 【1】输入源文件地址
# (1)输入地址
origin_path = input("请输入源文件地址 :>>>> ").strip()
# (2)对文件后缀进行校验 文本 / 二进数据
# D:\Python\PythonProjects\PythonProjects29\day12\user_data.txt
try:
type_file = origin_path.split('.')[-1] # txt
# 【2】打开源文件
if type_file in ['txt', 'text']:
with open(origin_path, 'r', encoding='utf8') as fp:
origin_data = fp.read()
elif type_file in ['mp4', 'jpg', 'png', 'webp', 'jpeg', 'zip']:
with open(origin_path, 'rb') as fp:
origin_data = fp.read()
except:
print(f"当前路径不存在!")
# 【3】输入新文件地址
target_path = input("请输入目标文件地址 :>>>> ").strip()
target_file_name = input("请输入目标文件名 :>>>> ").strip()
file_name, type_file = origin_path.split('\\')[-1].split('.')
if target_file_name:
target_file_name = target_file_name + '.' + type_file
else:
target_file_name = file_name + '.' + type_file
# target_path : D:\Python\PythonProjects\PythonProjects29\day12
# target_file_name : user_data.txt
target_path = target_path + '\\' + target_file_name
# 【4】写入新文件
if type_file in ['txt', 'text']:
with open(target_path, 'w', encoding='utf8') as fp:
fp.write(origin_data)
elif type_file in ['mp4', 'jpg', 'png', 'webp', 'jpeg', 'zip']:
with open(target_path, 'wb') as fp:
fp.write(origin_data)
# 【5】打印写入完后才能
print(f"当前目标文件 {target_file_name} 写入完成!")
标签:推导,异常,列表,try,user,print,input,data,字典
From: https://www.cnblogs.com/song1002/p/18136962