一、Iterable(可迭代对象)
1、可迭代对象:能够进行迭代操作的对象。
- 可以理解为:能够使用for循环遍历的都是可迭代对象;**
- 所有的可迭代对象,偶可以用内置函数iter转换为迭代器**
2、可迭代对象包括:
- 序列类型:元组、列表、字符串、range
- 字典、集合
- 文件对象(open(xxx))
- 实现了迭代协议(iter)方法的对象
class Myclass1:
"""
实现迭代协议
"""
def __iter__(self):
# return iter([111,22,33])
m = Myclass1()
for i in m :
print(i)
- 实现了序列语义方法(getitem)的对象
class Myclass2:
"""
实现序列语义
"""
value = [11,22,33]
def __getitem__(self, item):
return self.value[item]
m = Myclass2()
for i in m :
print(i)
二、Iterator(迭代器)
**1、迭代器:**实现了迭代器协议的对象(__iter__方法和__next__方法)。
- 能够使用内置函数next进行逐个迭代数据的对象
li = [111,222,333]
itor = iter(li)
print(next(itor))#每次使用next都能迭代出一个数据
print(next(itor))
2、特性:
- 迭代器内的数据只能迭代一次
- 当迭代器内部的数据,迭代完,,迭代器就会进入停止状态,如果再次通过next进行迭代就会抛出异常(StopIteration)
三、Generator(生成器;常用)
1、生成器:**生成器是迭代器的子类,可以把他当做一种特殊的迭代器,生成器支持支持迭代器所有的操作和特性。
2、生成器定义的方法:
- 生成器表达式
g = (i for i in xxx)
- 生成器函数:函数中使用了关键字yield的函数,都称之为生成器函数;生成器函数调用时不会直接执行,会直接返回一个生成器对象
def test1():
print("-------------1--------------")
yield 1
print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
yield 2
res = test1()
print(res)
这时打印出的test1函数为生成器对象
3、生成器的应用场景:
- 在程序中使用上万级别低的数据时,使用生成器来保存数据,可以显著的减少内存开销
- 生成器内部不直接保存数据,只存储生成数据低的规则(算法),使用next去获取才会生成(用的时候才生产)
- 可以使用生成器来实现函数内部的代码分段执行(pytest中的fixture实现,python3.5以前的携程实现
4、运行过程
当效用生成器函数时,他会返回一个生成器对象,该对象可以迭代获取生成器函数中通过yield语句产生的值。每次迭代时,生成器函数会从上一次yield语句的位置继续执行,直到再次遇到yield语句并产生下一个值,当超过迭代器中的数据全部取完以后,再取数据则会报错
5、自动化框架中用到的生成器
使用pytest执行
import pytest
@pytest.fixture()
def login_fixture():
print("=====用例前置脚本=====")
token = 'xxxxxxxx'
yield token
print("=====用例后置脚本=====")
def test_demo(login_fixture):
print("=====执行测试用例中=====")
上面的是pytest封装好的夹具功能,下面的代码是模拟完整的使用夹具的过程
from inspect import signature
def login_fixture():
print("=====用例前置脚本=====")
token = 'xxxxxxxx'
yield token
print("=====用例后置脚本=====")
def demo(login_fixture):
print("=====执行测试用例中=====")
if __name__ == '__main__':
#自动化测试框架中夹具是如何运行的
"""
1、框架初始运行时,会对所有夹具进行收集,
2、检测用例中是否使用到了夹具,若,则去夹具列表中查询同名的测试夹具
3、存在同名测试夹具,,先执行夹具的前置,再执行测试用例,最后执行夹具的后置脚本
"""
##检测函数中定义的参数
res = signature(demo).parameters
print(res)#OrderedDict([('login_fixture', <Parameter "login_fixture">)])
params = list(res.keys())
print(params)#['login_fixture']
#判断参数中是否有同名的测试夹具
#for key in params:
# pass
#如果存在对应的测试夹具,先执行夹具的前置脚本
f1 = login_fixture()
res = next(f1)
#再执行测试用例
demo(res)
#最后执行夹具的后置脚本
try:
next(f1)
except StopIteration:
pass
6、生成器的内置方法
- close方法:关闭生成器,关闭后无法再生成数据了
def work():
print("-------------1--------------")
s1 = yield 1
print("-------------2--------------s1=",s1)
s2 = yield 2
print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%s2=",s2)
yield 3
res = work()
print(next(res))
res.close()
print(next(res))
- send方法:和内置函数next一样,用来生成数据;但是send方法可以再生成数据的同时和生成器内部进行数据交换
- 使用send方法之前,必须先通过next去生成至少一次数据(通过next去启动生成器)
- send方法必须要传一个参数(值)且只能传一个
- send方法传入的值,会传到生成器内部上一次,挂起的yield处
def work():
print("-------------1--------------")
s1 = yield 1
print("-------------2--------------s1=",s1)
s2 = yield 2
print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%s2=",s2)
yield 3
res = work()
print(next(res))
print(res.send('test1'))#执行时先返回已定义的数据
print(res.send('test'))
结果:
- 主动生成器内部抛出异常(了解)
- 当调用 generator.throw(exc_type, exc_value, traceback) 时,会在生成器内部当前暂停的位置引发一个异常。生成器会尝试捕获这个异常,并在适当的位置执行相应的异常处理逻辑。如果生成器内部没有捕获到这个异常,或者异常处理逻辑中抛出了新的异常,那么这个异常会传播到生成器的调用处。
- 相当于在生成器内部上一次挂起的位置,执行raise,抛出异常
generator.throw(exc_type, exc_value=None, traceback=None)
- exc_type 表示要抛出的异常类型。
- exc_value 表示异常的值,默认为 None。
- traceback 表示异常的回溯信息,默认为 None。
PS:
回溯(traceback)信息是指当程序出现异常时,系统会生成一份包含异常发生位置及调用栈信息的报告。这份报告就是回溯信息。
回溯信息通常包含以下内容:
- 异常类型(Exception Type):表示引发异常的类型,例如TypeError、ValueError等。
- 异常值(Exception Value):表示异常的具体信息,通常是一个字符串,描述了异常的原因或相关信息。
- 回溯栈(Traceback Stack):表示调用栈信息,即异常发生时代码的执行路径,从最内部的函数或方法开始,逐步向外展示调用关系。
回溯信息可以帮助开发者追踪和定位异常发生的位置,以及异常抛出时的上下文信息。
在generator.throw()方法中,如果提供了回溯信息(traceback参数),那么该信息将包含在生成器捕获的异常中,使得异常的回溯信息更加完整。如果没有提供回溯信息,则系统会自动生成默认的回溯信息。