三大神器:迭代器, 生成器, 装饰器
迭代器
- 什么是迭代器(iter)
"""
容器; 程序中无法直接创建一个迭代器, 只能将别的序列转换成迭代器.
可变(只能取), 有序(但不支持下标)
特点: 打印迭代器无法查看所有元素, 也无法获取元素的个数; 获取元素的时候每次只能获取最前面的元素, 而且元素取一个就少一个.
语法:
变量 = iter(序列)
"""
- 查 - 获取元素
迭代器不管以什么样的方式获取到了某个元素, 那么这个元素一定会从迭代器中消失
取完了再取就报错了
"""
1) 查单个: next(迭代器) - 获取迭代器中最前面的那个元素
2) 遍历 - for-in
"""
生成器
关键字yield
- 什么是生成器
"""
容器; 其他容器是直接保存多个数据, 生成器保存产生多个数据的算法.
生成器获取数据的方式和特点和迭代器一样.
"""
- 创建生成器
"""
调用一个带有yield关键字的函数就可以得到一个生成器对象
"""
- 控制生成器产生数据的个数和值
"""
一个生成器产生的数据的个数和值,由创建生成器调用的那个函数的函数体在执行的时候会遇到几次yield, 以及每次yield后面的值来决定
个数: 由遇到的yield的次数决定
值: 由yield后面的数据决定
"""
- 生成器创建数据的原理
打印带尖括号的本质是序列的对象, 可以按迭代器, 生成器去使用
"""
每次获取生成器的数据的时候, 就会去执行创建这个生成器的函数题, 但是每次执行都只会执行到yield就停下来
"""
- 总结
生成器可以理解为一种特殊的程序执行规则, 而next与yield为告知程序执行生成器规则的标记
执行逻辑如下:
""" 主程序执行 遭遇next(变量) -> 进入变量保存的对象从头开始执行 -> 在函数中遭遇yield, 返回值并记录节点 -> 回到主程序执行next(变量)的下一步 -> 再次遭遇next(变量)(ps.和之前变量是同一个) -> 进入上次yield退出的节点,从yield下一条语句开始执行, ... """
每一个迭代器或生成器对象都是一次性用品
装饰器
- 什么是装饰器 - 给已经定义好的函数添加功能的工具
"""
装饰器就是一个函数, 这个函数既是实参高阶函数, 又是返回值高阶函数
"""
- 给函数添加功能
- 直接修改原函数
- 新建函数, 新函数中调用原函数
- 使用装饰器
无参装饰器
- 无参装饰器语法
"""
语法:
def 装饰器名(原函数):
def 添加完功能的新函数(*args, **kwargs):
调用原函数
添加新功能
return 添加完功能的新函数
语法细化:
def 装饰器名(f):
def new_f(*args, **kwargs):
result = f(*args, **kwargs)
新增功能
return result
return new_f
装饰器名 - 根据新增的功能来命名
"""
- 无参装饰器使用
"""
@无参装饰器名
定义函数
"""
有参装饰器
"""
语法细化:
def 装饰器名(参数列表):
def 无参装饰器(f)
def new_f(*args, **kwargs):
result = f(*args, **kwargs)
新增功能
return result
return new_f
return 无参装饰器
使用:
@有参装饰器名()
定义函数
"""
- 装饰器总结
装饰器的创建规则
无参 - 两层函数嵌套 + 特定返回值(外层返回新函数, 内层返回被装饰函数返回值相关值)
有参 - 三层函数嵌套 - 装饰器传参函数包裹无参装饰器, 传参函数返回值为无参装饰器
装饰器的调用规则
装饰器两种调用方法实际是两个不同的标记, 旨在告诉计算机程序接下来部分按什么逻辑顺序执行
- 无参 - @装饰器名
- 有参 - @装饰器名(装饰器使用的形参列表)
ps.语法中装饰器名为定义时最外层函数名
装饰器的调用运行逻辑
- 无参
""" @装饰器名 -> def 被装饰函数(形参列表): -> def new_fn(*args, **kwargs): -> 被装饰函数(实参) -> 执行new_fn并返回结果 """ """ 特殊规则的函数调用(将紧跟在后面定义的函数名作为实参传入装饰器函数运行) -> 进入装饰前函数,运行内容为定义了一个新函数,然后返回定义的新函数(@装饰器名 + 定义被装饰函数这个代码段的结果是得到了一个新函数, 当原函数在装饰器外的环境中被调用时, 新函数替代原函数进行响应. 因此, 即使新函数中不调用原函数, 新函数返回值与原函数毫无关联, 不返回原函数返回值, 也不会报错, 只是失去了身为装饰器的意义) -> 装饰器外部调用原函数, 执行装饰器内的新函数(调用时传的参数也一并传给新函数的形参), 并返回新函数的返回值 """ def add_tag(str1='p', str2='a'): def temp(fn): def new_fn(*args, **kwargs): return 0 return new_fn return temp @add_tag() def func1(x=0): if x: return 100 return 'abc' print(func1(1))
- 有参
""" @装饰器名(传给装饰器用的形参列表) -> def 装饰器名(装饰器用的形参列表): (ps.传参) -> def 任意函数名(被装饰函数名): -> 返回上一步定义的函数的函数名 """ """ 特殊调用规则的标记 -> 执行装饰器最外层函数(包括两部分内容: 定义一个函数(有且只有一个形参的函数) + 返回值(返回值为定义的这个函数的函数名)) 因此, 这里实际变化为@装饰器名() ==> @装饰器最外层函数返回的函数名 下一步就按无参装饰器执行规则进行 """
生成器与装饰器的两要点:
- 标记
- 执行规则
标记在于提示计算机接下来的执行规则是什么(相当于程序员和计算机之间定的暗号, 而计算机根据不同的标记去做不同的事情)
一个由语言开发者定义封装的计算机执行规则, 标记为规则激活的密码
生成器的标记为: 一个语法规则(next(生成器对象)), 一个关键字(yield)
装饰器的标记为: 一个语法规则(@装饰器名 + 定义的函数)
迭代器或许可以看作看不到yield关键字的生成器(因为没有必要看到)
迭代器内的代码猜测:
def iter(序列形参): for x in 序列形参: yield x
调用时
变量1 = iter(序列实参) # 序列实参传入函数, 返回一个生成器对象 变量2 = next(变量1) """ for x in 序列: -> yield返回序列中从最前面取出来的一个元素 """