一、可迭代对象
1. 容器类(能存放多个元素的数据类型):
① 序列:字符串、列表、元组、字节
② 字典
③ 集合
# 组件:开发社区写的一堆类
2. 迭代对象iteration
--- 可进行遍历的对象
> 可迭代对象都是Iterable的扩展类(子类、衍生类,派生类)
> 重写了__iter__(self),可以返回一个【迭代器】
--- 3.X所有可迭代对象都实现了__iter__(self),之前有的实现__getitem__
验证法:
from collections.abc import Iterable
print(issubclass(dict, Iterable))
3. 迭代器iterator
迭代器是迭代对象的特殊形式,即是迭代对象Iterable的子类
迭代对象无法遍历,迭代器下有next方法才能遍历,因此调用迭代对象下的迭代器才能遍历
迭代对象:不需要显式继承Iterable,只需要实现__iter__方法,返回迭代器
迭代器: 不需要显式继承Iterable,只需要实现__iter__方法和__next__方法,返回迭代器
(iter方法: 返回迭代器
next方法:获得单个元素)
> 如果通过next遍历元素,如果迭代器为空,返回StopIteration错误
> 迭代器是一次性的,被next遍历后元素消失
> for循环底层,每次都从迭代对象中,重新初始化一个迭代器
eg:
li = [1,2,4]
# 获取迭代器
① li.__iter__() # 魔法方法不支持显示调用
② li.iter
# 获得单个元素
① li.__nex__t()
② li.next
print(next(li))
li = [1,2,4]
# 获取迭代器
① li.__iter__() # 魔法方法不支持显示调用
② li.iter
# 获得单个元素
① li.__nex__t()
② li.next
print(next(li))
eg.# 模仿for循环底层
while True:
it = iter(li)
while True:
try:
item = next(it)
except StopIteration:
del it
break
4. 自定义迭代类型
满足抽象基础规范、
迭代对象: 实现iter方法,返回迭代器
迭代器 : next, iter方法返回自己
class My_Iterable:
def __iter__(self):
self.liter = [1,2,3,4]
return li.__iter__()
return My_Iteror(self.liter)
class My_Iteror:
def __init__(self, li):
self.liter = li
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.liter)
self.liter[self.index]
self.index += 1
return r
else:
raise StopIteration
m = My_Iterable()
it = iter(m)
print(next(it))
# 验证
print(isinstance(m, Iterable))
print(issubclass(My_Iterable, Iterable))
迭代器 :只能用一次
迭代对象:用来产生迭代器,可以狗仔复杂数据类型,提供给迭代器使用
5. 迭代器缺点:
(1) 实现一个迭代器,需要iter,next方法
(2) 不使用for循环,需要自己去捕获StopIteration异常
(3) 一次性数据全部迭代,结果不一定全部使用,占用内存
二、 生成器
--- 2.5后出现的可迭代对象,即底层使用了迭代器实现
1. 定义:
懒加载(按需加载)的迭代器
2. 生成器的特征
生成器不会一次性计算出存储的数据,而是一次只计算一个数据
3. 生成器的实现:
> 生成器的数据获得方式:
① next
② 遍历
3.1 生成器表达式
元组生成式 = 生成器
x = (i**2 for in range(5))
print(next(x))
3.2 生成器函数
--- 带有yield关键字的函数
yield: 能够让程序暂停到yeild位置,产出值
注意:生成器函数调用时,不是直接执行,而是创建生成器对象,
> 生成器可能包含多个yield
> 生成器底层是迭代器
> 可以通过next方法获得内部远胜于,也可以通过for遍历
> 当函数终止时,再次获取元素,报StopIteration异常
> 函数执行遇到yiled,程序暂停在该位置,返回对应值,将控制前交给调用者
def f():
print('函数开始')
for i in range(1, 101):
print('yield前;')
yield i # 暂停,产出返回值i
print('yield后:',i)
return i
g = f()
next(g)
next(g)
3.3 yield表达式
生成器:
校核值 = yield 产出值
调用端:
产出值 = send(校核值)
第一次调用生成器:产生生成器对象
next:激活生成器
> 生成器表达式的结果 是 调用生成器send方法传入的参数
> 对象.send(None) == next(对象)
> 激活生成器:① next()
② send(None),必须是None
> 获取生成器元素
next(g)
g.send('随意')
def gen():
for i in range(100):
value = yield i**2
# value是send函数传入值,i**2为产出值,两者不会赋值,互不相干
# value是send传入的参数,i是send或者next返回值
print(f'value={value}')
g = gen() # 创建对象
print(next(g)) # 激活生成器,传出0
print(g.send('玩一玩')) # value = '玩一玩,返回值为i
pl.需求,产生1 2 3 4 5,提示,输出5 4 3 2 1,....
pl.需求,产生1 2 3 4 5,提示,输出5 4 3 2 1,....
# 编写生成器,调整生成方案
import time
def gen():
msg = ''
while True:
x = yield msg
if x == 5:
mag = 'too big'
elif x == 1:
msg = 'too small'
g = gen()
# 在主线插入生成器调用
while True:
time.sleep(0.5)
print(x)
msg = g.send(x)
if msg = 'too big':
x -= 1
else msg == 'too small'
x += 1
三、 装饰器
> 装饰器的作用:
(1) 扩展函数
(2) AOP(面向切面):将共用模块提取出来,形参一个单独组件
1. 闭包
--- 在内部函数中访问外部函数的变量;
在外部函数中返回内部函数的函数名(调用)
(1) 条件:
① 嵌套函数
② 内部函数能够访问外围变量
③ 外部函数return 内部函数名
eg.
def outer():
x = 1
sef inner():
print(x)
return inner
a = outer()
print(a.__closure__)
(2) 适用情形
① 函数中有一些变量在被调用后仍然希望保留’
② 函数需要扩展功能,但是不能修改原函数的名字
# 原始
from datetime import datetime
def on_duty(name):
print(f'{name}在上班')
def off_duty(name):
print(f'{name}离开了')
print(datetime.now())
# 闭包,不修改原始功能,添加新功能
def new(func):
def inner(name):
func(name)
print('添加性能')
return inner
on_duty = new(on_duty)
on_duty('Geoffrey')
2. 装饰器的作用:
> 用来处理被装饰的函数,返回函数的新名字,采用了闭包的思想
> 在不修改原函数的基础上,对现有函数进行扩充、功能扩展
(1) 格式
在被调用函数上面加 @装饰名
--- 一种语法糖
原函数名 = 装饰函数(被装饰函数)
def new(func):
def inner(name):
func(name)
print('添加性能')
return inner
@new
def on_duty(name):
print(f'{name}在上班')
3. 装饰器的优化
(1) 参数的优化 --- 万能参数
(2) 返回值的优化
---- 在inner中,提取func返回值作为inner返回值
(3) 装饰器的叠加
--- 使用装饰器扩展更多的功能,
from functools import wraps
def record(*args):
def _inner(func):
@wraps(func) # 保留原函数的元信息
def __inner(*arg, **kwarg): # 万能参数
r = func(*arg, **kwarg)
print(f'{args[0]}天后去{args[1]}向领导汇报工作')
return r
return __inner
return _inner
# 测试嵌套装饰器
def new(func): # 为原函数添加的新功能
def inner(*args, **kwargs):
r = func(*args, **kwargs) # 添加返回值
print('new装饰器添加性能')
return r # 此处对应原函数返回值
return inner
@record(20, '上海')
@new
def on_duty(name):
print(f'{name}在上班')
on_duty('Geoffrey')
4. 含有参数的装饰器
--- 如果装饰器中需要使用其他参数,在外部做一个闭包
在装饰原函数的时候,在装饰器后面加上(参数)
不要在装饰器层传入参数,装饰器层只传入函数名
5. 保留元信息 (函数注释)
functools 下的 wraps实现元信息的保留
在inner层上面添加:
@wraps(func) --- 形式参数func
6. 类装饰器
--- 实现装饰器,除了装饰器函数,还可以使用类方法
class New:
def __init__(self, func):
self.func = func
#使对象能通过方法调用,即执行 对象()
def __call__(self, *args, **kwargs):
self.func(*args, **kwargs)
print('随便添加其他函数')
@new
def play(a, b):
from datetime import datetime
print(datetime.now())