python——异常处理 文件

一、异常处理机制

异常的定义:程序运行时发生的不正常事件。

一般情况下,程序遇见异常bug就会终止运行,试想一下现实世界中,程序遇见小小的bug就直接死机,可以吗?——很不好。

怎么解决呢?

使用异常处理机制,捕获异常,处理异常。

异常分为:内置异常、自定义异常。

1.1 常见的内置异常

# print(name) # NameError: name 'name' is not defined 
# print(int('100a'))
# ValueError: invalid literal for int() with base 10: '100a' 
# print('hello' + 1234) 
# TypeError: can only concatenate str (not "int") to str 
# ls = [1] # print(ls[10]) 
# IndexError: list index out of range 
# if 1: # print("我是真的") 
# IndentationError: expected an indented block after 'if' statement on line 14 
# s1 = 'hello' 
# print(s1.name) 
# AttributeError: 'str' object has no attribute 'name' 
# print(3/0) 
# ZeroDivisionError: division by zero 
# import hahaha # ModuleNotFoundError: No module named 'hahaha' 
# f = open('hahaha.txt', 'r') 
# FileNotFoundError: [Errno 2] No such file or directory: 'hahaha.txt'

1.2 内置异常处理

异常处理是对异常进行捕获、抛出、处理,提高程序健壮性的机制。

算法的设计要求:正确性、可读性、健壮性、高效率、低存储

使用关键字try except finally else组合成不同的处理方式,其中try和except是核心。

简单模式:
语法
try:
    代码1
except:
    代码2

例子:
try:
    print(name)
except:
    print('命名错误')

捕获多个异常结构
语法:
try:
    代码块
except XXX:
    代码2
except XXX:
    代码3
except XXX:
    代码4
    
例子:
try:
    print('hello' + 1234)
except NameError:
    print("命名错误")
except TypeError:
    print("类型错误")
except IndentationError:
    print("缩进错误")
    
try:
    print('hello' + 1234)
except (NameError, TypeError, IndentationError):#从中匹配一个
    print("有错误")
    
try:
    print('hello' + 1234)
except Exception as e:
    print(f"有{e}错误")

try...except...else结构
语法:
try:
    代码1
except:
    代码2
else:
    代码3
    
例子:
try:
    a = 3
    b = 0
    c = a/b
except Exception as f:
    print(f) #division by zero
else:
    print(c)
try...except...else...finally结构
语法:
try:
    代码1
except:
    代码2
else:
    代码3
finally:
    代码4
    
例子:
try:
    a = 3
    b = 0
    c = a/b
except Exception as f:
    print(f) #division by zero
else:
    print(c)
finally:
    print("我会一直在")

练习: 1、使用异常处理,定义一个函数func(listinfo)listinfo为列表, listinfo = [133, 88, 24, 33, 232, 44, 11, 44], 返回列表中小于100且为偶数的数。

listinfo = [133, 88, 24, 33, 232, 44, 11, 44]
try:
    l = [i for i in listinfo if i%2==0 and i<100]
except Exception as e:
    print(e)
else:
    print(l) #[88, 24, 44, 44]
# finally:
#     print('就这样')

1.3 自定义异常

python放入内置异常已经很丰富了,但是我们还是可以自定义异常的,也就是说我们可以根据自己的实际需求做异常判断。

在学习自定义异常之前,先来看一下 raise的使用。

raise可以手动抛出异常——内置异常或者自定义异常都可以。

def sub(a, b):
#定义一个两个数商的函数(当除数为0报出错误)
def sub(a,b):
    if b == 0:
        raise Exception('除数不能等于0')
    else:
        return a/b

try:
    print(sub(2,0))
except Exception as e:
    print(e) #除数不能等于0

现在来看一下自定义异常类,自定义异常必须继承Exception类

语法格式:
class MyException(BaseException):
    def __init__(self, msg):
        self.msg = msg
    def __str__(self):
        return self.msg
        
try:
    raise MyException('异常消息字符串')
except MyException as e:
    print(e)
class error(BaseException):
    def __init__(self,num):
        self.num = num
    def __str__(self):
        return self.num


def sub(a,b):
    if a<b:
        raise error('被减数不能小于减数')
    else:
        return a-b

try:
    print(sub(2,3))
except Exception as e:
    print(e)

练习:

编写一个 Drugs 药品类,添加一个类属性,产地 place 为江中集团 添加一个类方法,方法名自定义,实现修改类属性的值,将产地修改为中国 添加构造方法,实例属性如下:name(名称),out_time(过期时间)默认值为 2024-09-16 添加查询剩余保质期的方法 get_time,输出当前时间与过期时间的差值,单位为天, 使用异常捕获差值信息,如果是大于等于 0 的话,则正常输出,如果小于 0 的话, 则抛出异常,异常信息为当前药品已过期,并捕获该异常

class Drugs:
    place = '江中集团'
    def __init__(self,name,out_time = 50):
        self.name = name
        self.out_time = out_time
    @property
    def id(self):
        return f"产地{self.__id}"
    @id.setter
    def id(self,new_id):
        self.__id = new_id
    def get_time(self,new_time):
        self.out_time-=new_time

class error(BaseException):
    def __init__(self,num):
        self.num = num
    def __str__(self):
        return self.num

n = Drugs('阿莫西林')

def a(x):
    n.get_time(x)
    if  n.out_time<0:
        raise error('已经过期不能吃了')
    else:
        print(f'药还剩{n.out_time}天')

try:
    a(60)
except error as e:
    print(e)

 

1.5 demo2:日志的简单应用

在python中,记录日志使用logging库,日志的级别从高到低分别为:

  1. CRITICAL:系统崩溃级别的错误,必须立即处理
  2. ERROR:运行时的错误,可能导致程序无法正常运行
  3. WARNING:警告信息
  4. INFO:信息性消息,程序正常运行
  5. DEBUG:详细信息,通常在诊断问题时有用
import logging
# 设置日志的打印级别
# logging.basicConfig(level=logging.DEBUG)
logging.critical('这是一个critical信息')
logging.error('这是一个error信息')
logging.warning('这是一个warning信息')
logging.info('这是一个info信息')
logging.debug('这是一个debug信息')
# 向指定的日志文件里去打印日志信息
import logging
# logging.basicConfig(filename='./app.log')
# logging.warning('这是一个warning信息')

# logging.basicConfig(filename='./app.log', level=logging.DEBUG, filemode='a',
#                     format='%(name)s - %(levelname)s - %(message)s')
# logging.warning('这是一个warning信息')

# %(name)s    日志记录器的名字
# %(levelname)s    日志级别
# %(asctime)s    时间
# %(message)s    消息本身

二、文件操作

2.0 文件操作的重要性和应用场景

重要性
  1. 数据持久化
  2. 跨平台兼容性
  3. 数据备份与恢复
  4. 数据共享
  5. 配置管理
  6. 日志记录
应用场景
  1. 数据分析
  2. web开发
  3. 文本处理

2.1 文件的基本概念

2.1.1 文件的概念

文件是一个存储在某种持久性存储介质【硬盘、光盘、磁盘等】上的数据的结合。

文件可以包含各种类型的信息:文本、图像、音频、视频、应用程序代码以及其他类型的二进制数据。

文件通常由数据、元数据、文件系统等几部分组成。

文件的属性有:文件名、位置、文件类型、文件大小、创建日期、修改日期、访问权限。

2.1.2 文件的分类

windows系统下大致分为以下几种:

  1. 文本文件:包含可读字符的文件,如.txt .csv .py .html等
  2. 二进制文件:包含不可直接读的原始二进制数据的文件,如.exe .jpg .mp3等
  3. 可执行文件:可以被操作系统执行的文件,如.exe
  4. 数据文件:用于存储应用程序数据的文件,如数据库文件、配置文件等
  5. 目录/文件夹:用于组织和管理其他文件的特殊文件

在Linux系统下,有以下几种:

  1. - 普通文件
  2. d 目录文件
  3. b 块设备文件【底层驱动文件】
  4. c 字符设备文件【底层驱动文件】
  5. l 链接文件【类似于快捷方式】
  6. p 管道文件,用于进程间的通信
  7. s 套接字文件,用于网络通信的端点
文本文件:
  • 文本文件是由单一特定编码组成的文件,如UTF-8编码。
  • 由于存在编码,文本文件也被看成是存储着数据的长字符串。
二进制文件:
  • 直接由比特0和1组成,没有统一字符编码
  • 一般都存在二进制0和1的组织结构,即文件格式
s = 'hello world!'

print("文本文件:", s)
print("二进制文件:", s.encode())

2.1.3 文件位置【路径】

在计算机系统中,路径是用来表示文件位置的一种方式。

路径又分绝对路径和相对路径。

windows系统下:

绝对路径:带有盘符的或者带有网址的

C:\Users\admin\Desktop\py_gj\py_day3

相对路径:

./py_gj/py_day3

../py_gj/py_day3

这里的点有特殊含义,一个点表示当前路径下,两个点表示上一级路径下。

path = "C:\\Users\\admin\\Desktop\\py_gj\\py_day3" print(path) 
path1 = './day3.3.py' print(path1) #本级目录
path2 = "../py_day2/day2.2.py" print(path2)#上一级目录

2.2 文件的操作

2.2.1 打开文件open

如果想用open读取文件,那么先来看一下它的语法格式:

open(file, [mode='r', buffering=-1, encoding=None])

参数:

  • file: 必需,文件路径(相对或者绝对路径)
  • mode: 可选,文件打开模式,默认为r
  • buffering: 可选,设置缓冲
  • encoding: 可选,一般使用utf-8

返回值:一个文件对象

mode常用的模式:

打开方式

功能

文件存在时

文件不存在时

r

只读方式打开文件

打开

报错

r+

以读写方式打开文件

打开

报错

w

只写方式打开文件

打开(清空之前内容)

新建

w+

以读写方式打开文件

打开(清空之前内容)

新建

a

以追加方式打开文件(写)

打开,保留之前内容

新建

a+

以读写方式打开文件

打开,保留之前内容

新建

mode参数还可以指定以什么样的编码方式读写文本,默认情况下open是以文本形式打开文件的,比如上面的四种mode模式。

当我们需要以"字节[二进制]"形式读写文件时,只需要在mode参数的后面加 b 就可以了。

  1. rb 以二进制形式打开一个文件,只读
  2. wb 以二进制形式打开一个文件,只写
  3. wb+ 以二进制形式打开一个文件,读写

demo1:读取文件

  1. 我们在同级目录下创建一个名为111的txt文本文件,同时创建一个test.py文件,通过代码去读取其中的内容。
  2. 我们在111.txt中写入两行内容: Life is short, You need Python 人生苦短,我用python
  3. 然后在test.py中写入读取代码

 

2.2.2 with关键字

当我们使用open直接打开文件,进行文件操作后,需要使用close进行文件保存和关闭。但是这种方式不是最好的,为什么呢?因为在文件操作过程中一旦有报错,那么文件还能正确关闭吗?——不能

如何解决呢?——使用 with 关键字

优点:当我们操作文件的代码块结束后,文件会正确关闭,即便文件操作报错,也会正确关闭,无需手动调用close()

with open('./111.txt', encoding='utf-8') as f:
    read_data = f.read()
    print(read_data)

2.2.3 关闭文件close()

语法格式:
file.close()

2.2.4 read()方法

语法格式:
f.read(size) # f为文件对象

参数:

  • size(可选):为数字,表示从已打开文件中读取的字节计数,默认值为-1,默认情况下为读取全部。
with open('./111.txt', encoding='utf-8') as f:
    read_data = f.read(5)
    print(read_data)

2.2.5 readline()方法与readlines()方法

readline()方法

注意 readline()方法会记住上一个readline()读取的位置,接着读取下一行。 

 

readlines()方法

 

2.2.6 write()方法

在python中使用write()方法将字符串写入文件中。

f.write(str) # f为文件对象

参数:

  • str代表要写入的字符串

demo:

 

2.2.7 文件指针定位

python中文件读写,定位文件读写的指针会随着不断地读写而移动。所以我们想要正确的读写,就需要控制指针的定位。

f.tell()
功能:返回文件的当前位置,即文件指针当前位置

f.seek(offset[, whence])
功能:将文件内部光标定位到指定的位置
参数:offset:开始的偏移量,也就是代表需要移动偏移的字节数
     whence:可选,默认值为 0,
	  
             0代表从文件开头开始算起
	  
             1代表从当前位置开始算起
	  
             2代表从文件末尾算起
eg:
f.seek(p,0)  移动到文件第p个字节处,绝对位置

f.seek(p,1)  移动到相对于当前位置之后的p个字节

f.seek(p,2)  移动到相对文章尾之后的p个字节


f.seek(0,0)  移动到文件开头
             
s = "Hello, world!"

with open('./binary.txt', mode='wb+') as f:
    f.write(s.encode())
    f.seek(2,0) # 从开头 偏移2个
    f.seek(2,1) # 从当前 偏移2个
    f.seek(2,2) # 从末尾 偏移2个
    f.seek(0,0)
    data = f.read(1)
    print(data)

2.3 目录的操作

import os

try:
    os.mkdir('./t1')
except Exception as e:
    print(e)

try:
    os.rmdir('./t1')
except Exception as e:
    print(e)

try:
    os.makedirs('./t1/t2')
except Exception as e:
    print(e)

练习:将 1-100 之间能被 5 整除的数保存在列表 numbers 中 1. 将 numbers 中的元素写入到文件 num.txt 中 2. 使用文件操作方式打开 num.txt 文件读取内容,并计算它们的平均数

# 将 1-100 之间能被 5 整除的数保存在列表 numbers 中
# 1. 将 numbers 中的元素写入到文件 num.txt 中
# 2. 使用文件操作方式打开 num.txt 文件读取内容,并计算它们的平均数
l = [i for i in range(1,101) if i%5==0]
with open('./num.txt',mode='w') as f:
    for i in l:
        f.write(str(i)+'\n')
with open('./num.txt',mode='r') as f:
    sum = 0
    for i in f.readlines():
       sum+=int(i)
    print(sum/len(l))#52.5

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值