一、with语句
作用:自动释放资源,出现异常也能关闭;用来处理上下文管理器对象的
例题1、读取文件内容
f = open("./1.txt", 'r', encoding='utf-8')
print(f.read())
f.close()
上述代码存在的问题:1. 如果目标文件不存在,会报错
2. 手动close()如果忘记的话,会比较浪费资源
解决方案1:如果目标文件不存在,会报错,捕获异常
try:
# 尝试执行的代码
f = open("./1.txt", 'r', encoding='utf-8')
print(f.read())
except IOError as e:
# 出问题后的解决方案, 文件不存在就创建
f = open("./1.txt", 'w', encoding='utf-8')
finally:
# 释放资源.
f.close()
解决方案2:with open()写法
with open('1.txt', 'r',encoding='utf-8') as f:
# 这里的内容执行完毕后, 会被自动释放资源.
print(f.read())
可以明显看出,with 的写法更简便
2、上下文管理器
概述:一个类只要实现了__enter__()和__exit__(),则该类创建的对象就是上下文管理器
例题2:演示上下文管理器,解释 with open() 的原理
1. 自定义上下文管理器类
class MyFile:
# 2. 重写 __init__()魔法方法, 初始化: file_name(文件名), file_model(文件模型)
def __init__(self, file_name, file_model):
"""
初始化属性的
:param file_name: 文件名
:param file_model: 文件(操作)模型, r:只读, w:只写, a:追加
"""
self.file_name = file_name
self.file_model = file_model
self.fp = None # fp代表的文件对象.
# 3. 重写 __enter__()函数, 表示: 上文. 即: with语句执行前, 做的事儿
def __enter__(self):
print('这个是上文, 初始化属性的!')
self.fp = open(self.file_name, self.file_model, encoding='utf-8')
return self.fp # fp就是文件对象.
# return self # 返回MyFile类的对象,走6
# 4. 重写 __exit__()函数, 表示: 下文, 即: with语句执行完毕后, 做的事儿
def __exit__(self, exc_type, exc_val, exc_tb):
print('这个是下文, 释放资源的!')
self.fp.close()
# 5. 演示with open()语法, __enter__()返回的是: 文件对象
with MyFile('./1.txt', 'r') as fp:
# 这里的内容执行完毕后, 会被自动释放资源
print(fp.read())
# 6. 演示with open()语法, __enter__()返回的是: MyFile类的对象, 即: 上下文管理器类的对象
# with MyFile('./1.txt', 'r') as mf:
# # 这里的内容执行完毕后, 会被自动释放资源.
# print(mf.fp.read())
二、math包
ceil( ) 天花板数:获取比这个数字大的所有整数中,最小的那个整数
例如:ceil(12.0) → 12
ceil(12.1) → 13
ceil(12.9) → 13
import math
math.ceil(i) # 获取比i大的最小整数
三、生成器
1、作用:根据程序员写的规则,快速生成数据,降低能耗
2、写法:生成器对象 =(生成器规则) # 小括号是生成器,不是元组的意思
例题:演示生成器写法
列表推导式:
my_list = [i for i in range(1, 6)]
print(my_list) # [1, 2, 3, 4, 5]
集合推导式:
my_set = {i for i in range(1, 6)}
print(my_set)
生成器:
my_generator = (i for i in range(1, 6))
print(my_generator) # 直接打印, 打印的是 生成器对象的地址
发现打印的是生成器的地址,如何获取数据呢?
方式1:遍历
for i in my_generator:
print(i)
方式2:使用 next( )调用1次,获取1个结果
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
四、yield i
作用:将数据 i 封装到生成器中,自动返回生成器对象
# 1. 定义函数, 获取1 ~ 5之间所有的数据, 封装到生成器中, 并返回
def get_generator(n):
"""
演示yield关键字, 它会将数据封装到生成器中, 并返回
:param n: 要生成的数字的区间
:return: 无
"""
for i in range(1, n + 1):
# 使用 yield关键字 把数据存储到生成器中
yield i # yield作用: 把数字i封装到生成器中, 函数执行完毕后, 返回生成器对象
# 2. 调用 get_generator()函数, 获取生成器对象
g = get_generator(17)
print(g) # 生成器对象
# 3. 从生成器中获取数据.
for i in g:
print(i)
综合案例
需求:把给定的文件(100条数据)按照每批次8条的形式,分批包装到 生成器中,并返回该生成
器对象
# 1. 导包.
import math
# 2. 定义函数, 用于获取生成器, 即: 封装每批次的数据
def dataset_loader(batch_size):
"""
编写生成器代码, 用于将文件中的数据, 分批次, 封装到: 生成器中
:param batch_size: 每批次, 多少条数据
:return: 无
"""
# 2.1 读文件
with open('./1.txt', 'r', encoding='utf-8') as f:
lines = f.readlines() # lines变成一个列表
# 2.2 计算总条数
count = len(lines)
# 2.3 计算一共多少批
batch_count = math.ceil(count / batch_size)
# 2.4 根据批次数量, 封装到 生成器中, 并返回
for idx in range(batch_count):
yield lines[idx * batch_size : idx * batch_size + batch_size]
if __name__ == '__main__':
# 3. 调用函数
my_loader = dataset_loader(8) # 8条为一批
# 4. 遍历生成器, 获取到每批数据
# 获取第1批
print(next(my_loader))
for data in next(my_loader):
print(data, end='')
# 第2批
for data in next(my_loader):
print(data, end='')
# 查看每一批
for data in my_loader:
print(data)
五、property
1、作用:把方法当属性使用,可以简化代码
2、用法:
1. 充当装饰器
@property 修饰获取值的方法
@属性名.setter 修饰设置值的方法,属性名要和@property修饰的函数名保持一致
2. 可以修饰类变量
类属性名 = property(get_方法名,set_方法名)
3、例子:
充当装饰器的用法:
# 1. 定义Person类, 有1个私有属性age, 尝试在外访问 私有的age变量
class Person:
# 初始化1个私有的 变量 age
def __init__(self) -> None:
self.__age = 20 # 私有的 对象属性
# 为了让外界访问 类中私有内容, 我们可以提供公共的访问方式
# 不使用装饰器
# def get_age(self):
# return self.__age
#
# def set_age(self, age):
# self.__age = age
# 使用装饰器
@property
def age(self):
return self.__age
@age.setter # @property修饰的函数名.setter
def age(self, age):
self.__age = age
if __name__ == '__main__':
# 不使用装饰器
# 2 创建Person类的对象, 尝试调用 age属性
# p = Person()
# 访问变量
# print(p.get_age()) # 20
# 修改变量
# p.set_age(30)
# 访问变量
# print(p.get_age()) # 30
# 使用装饰器
# 2. 创建Person类的对象, 尝试调用 age属性
p = Person()
# 访问变量
print(p.age) # 20
# 修改变量
p.age = 30
# 访问变量
print(p.age) # 30
修饰类变量用法:
# 1. 定义Person类, 有1个私有属性age, 尝试在外接访问 私有的age变量
class Person:
# 初始化1个私有的 变量 age
def __init__(self) -> None:
self.__age = 20 # 私有的 对象属性
# 修饰之后, 就可以在外界把age当做类属性来使用了
age = property(get_age, set_age) # 类属性
if __name__ == '__main__':
# 类属性的用法
p = Person()
print(p.age) # 获取值
p.age = 30 # 设置值
print(p.age) # 获取值
恭喜你!任务完成,要多多练习哟~