迭代器入门
python
"""
案例: 演示自定义迭代器.
迭代器介绍:
概述:
自定义的类, 只要重写了 __iter__() 和 __next__() 方法, 就可以称为 迭代器.
目的:
隐藏底层的逻辑, 让用户使用更方便.
惰性加载, 用的时候才会获取.
回顾: for循环格式
for i in 可迭代类型:
pass
"""
# 需求: 模拟range(1, 6), 自定义 迭代器实现同等逻辑.
# 场景1: 回顾 range()用法.
for i in range(1, 6):
print(i)
print('-' * 23)
# 场景2: 自定义迭代器.
# 1. 自定义 迭代器类.
class MyIterator:
# 2. 通过init魔法方法, 初始化属性, 指定: 范围.
def __init__(self, start, end):
self.current_value = start # 当前值, 默认为 开始值.
self.end = end # 结束值.
# 3. 重写iterator魔法方法, 返回当前对象(即: 迭代器对象).
def __iter__(self):
return self
# 4. 重写next魔法方法, 返回当前值, 并更新当前值.
def __next__(self):
# 4.1 判断当前值范围是否合法.
if self.current_value >= self.end:
raise StopIteration # 抛出异常, 迭代结束.
# 4.2 走这里, 说明当前值合法, 返回当前值, 并更新当前值.
# value = self.current_value # value = 1 2 3 4 5
# self.current_value += 1 # self.current_value = 2 3 4 5 6
# return value # 1 2 3 4 5
# 效果同上, 代码更简单
self.current_value += 1 # self.current_value = 2 3 4 5 6
return self.current_value - 1 # 1 2 3 4 5
# 5. 创建迭代器对象, 并遍历.
# 5.1 for循环
for i in MyIterator(1, 6):
print(i)
print('-' * 23)
# 5.2 next()函数
my_itr = MyIterator(10, 13)
print(next(my_itr)) # 10
print(next(my_itr)) # 11
print(next(my_itr)) # 12
# print(next(my_itr)) # raise StopIteration # 抛出异常, 迭代结束.
生成器介绍
-
案例1: 推导式写法
python""" 案例: 演示生成器之 推导式写法. 生成器介绍: 概述: 所谓的生成器就是基于 数据规则, 用一部分在生成一部分, 而不是一下子生成完所有. 目的: 可以节省大量的内存. 实现方式: 1. 推导式写法. 2. yield关键字 """ import sys # system: 系统模块 # 场景1: 生成器 推导式写法. # 需求1: 生成1 ~ 10之间的整数. my_generator = (i for i in range(1, 11)) #这里使用的是() print(my_generator) print(type(my_generator)) # <class 'generator'> print('-' * 23) # 需求2: 生成 1 ~ 10 之间的偶数. my_gt2 = (i for i in range(1, 11) if i % 2 == 0) print(my_gt2) print('-' * 23) # 需求3: 如何从生成器中获取数据. # 思路1: next() print(next(my_gt2)) # 2 print(next(my_gt2)) # 4 print('*' * 23) for i in my_gt2: print(i) # 6, 8, 10 print('-' * 23) # 验证 生成器的目的 就是可以减少内存占用. my_list = [i for i in range(1000000)] my_gt3 = (i for i in range(1000000)) print(type(my_list), type(my_gt3)) # 查看my_list的内存空间占用. print(f'my_list的内存占用: {sys.getsizeof(my_list)}') # 89095160 print(f'my_gt3的内存占用: {sys.getsizeof(my_gt3)}') # 192 print('-' * 23) -
案例2: yield关键字
python""" 案例: 演示生成器之 推导式写法. 生成器介绍: 概述: 所谓的生成器就是基于 数据规则, 用一部分在生成一部分, 而不是一下子生成完所有. 目的: 可以节省大量的内存. 实现方式: 1. 推导式写法. 2. yield关键字 """ # 需求: 通过yield方式, 获取到生成器之 1 ~ 10之间的整数. # 回顾: 推导式写法. my_g = (i for i in range(1, 11)) # yield方式如下. # 1.定义函数, 存储到生成器中, 并返回. def my_fun(): # yield在这里做了三件事儿: 1.创建生成器对象. 2.把值存储到生成器中. 3.返回生成器. for i in range(1, 11): yield i # 2.测试. my_g2 = my_fun() print(type(my_g2)) # <class 'generator'> print(next(my_g2)) print(next(my_g2)) print('-' * 23) for i in my_g2: print(i) -
案例3: 批量歌词
python""" 案例: 基于传入的数值(每批次的歌词条数), 创建 生成器, 生成批次歌词. """ import math # 需求: 基于文件中 周杰伦的歌词, 创建生成器, 根据传入的每批次的歌词条数, 生成歌词批次. # 1. 定义函数, 接收 每批次的歌词条数, 返回生成器. def dataset_loader(batch_size): # 假设是 8条/批次 """ 自定义的 歌词 批量生成器 :param batch_size: 每批次的歌词条数 :return: 生成器, 每个元素都是一批次的数据, 例如: (8条, 8条, 8条...) """ # 1.1 读取文件数据. with open('./data/jaychou_lyrics.txt', 'r', encoding='utf-8') as src_f: # 1.2 一次读取所有行. # lines = [line.strip() for line in src_f.readlines()] lines = src_f.readlines() # 1.3 计算批次总数, 假设: 5批 total_batch = math.ceil(len(lines) / batch_size) # 1.4 for循环方式, 获取到每批次的数据, 放到生成器中, 并返回. for idx in range(total_batch): # idx的值: 0, 1, 2, 3, 4 # 第1批歌词, 批次索引(idx=0), 歌词为: 第1条 ~ 第8条, 索引为: 0 ~ 7 # 第2批歌词, 批次索引(idx=1), 歌词为: 第9条 ~ 第16条, 索引为: 8 ~ 15 # 第3批歌词, 批次索引(idx=2), 歌词为: 第17条 ~ 第24条, 索引为: 16 ~ 23 yield lines[idx * batch_size : idx * batch_size + batch_size] # 第1批 # 2. 测试. dl = dataset_loader(8) print(next(dl)) # 第1批 print(next(dl)) # 第2批 for batch_data in dl: print(batch_data)
Property属性介绍
-
场景1: 装饰器用法
python""" 案例: 演示property属性的用法. property属性介绍: 概述/目的/作用: 把 函数 当做 变量来使用. 实现方式: 方式1: 装饰器. 方式2: 类属性. property的装饰器用法: @property 修饰 获取值的函数 @获取值的函数名.setter 修饰 设置值的函数 之后, 就可以直接 .上述的函数名 来当做变量直接用. """ # 需求: 定义学生类, 私有属性 age, 通过property实现简化调用. # 1. 定义学生类. class Student: # 1.1 私有属性. def __init__(self): self.__age = 18 # 1.2 提供公共的方式方式 @property def age(self): return self.__age @age.setter def age(self, age): # 可以在这里对传入的age值做判断, 但是一般不做, 重要字段才会做判断. # 因为实际开发中数据是从前端传过来的, 已经做过判断了, 这里做属于二次校验. self.__age = age # 2. 测试 if __name__ == '__main__': # 2.1 创建学生对象. s = Student() # 2.2. 设置值 s.age = 20 # 2.3 获取值 print(s.age) -
场景2: 类属性
python""" 案例: 演示property属性的用法. property属性介绍: 概述/目的/作用: 把 函数 当做 变量来使用. 实现方式: 方式1: 装饰器. 方式2: 类属性. property的装饰器用法: @property 修饰 获取值的函数 @获取值的函数名.setter 修饰 设置值的函数 property类属性的用法: 类属性名 = property(获取值的函数名, 设置值的函数名) 之后, 就可以直接 .上述的函数名 来当做变量直接用. """ # 需求: 定义学生类, 私有 age属性, 通过property充当类属性用. # 1. 定义学生类. class Student: # 1.1 私有age属性. def __init__(self): self.__age = 20 # 1.2 公共的访问方式. def get_age(self): return self.__age def set_age(self, age): self.__age = age # 1.3 封装上述的公共方式为 类属性 # 参1: 获取值的函数名, 参2: 设置值的函数名 age = property(get_age, set_age) # 2. 测试 if __name__ == '__main__': # 2.1 创建学生对象. s = Student() # 2.2. 设置值 s.age = 99 # 2.3 获取值 print(s.age)