python 11 列表解析、迭代器、生成器函数

目录

一、列表解析

二、迭代器

1、概念

2、为什么要有迭代器?什么是可迭代对象?什么是迭代器对象?

3、迭代器对象的使用

4、for 循环调用迭代器

5、迭代器的优缺点

二、生成器函数

1、什么是生成器函数

2、send() 方法

3、close() 方法

4、throw() 方法


一、列表解析

    把一个表达式映射遍一个序列,将其结果收集到一个新的列表并返回。

l = [ord(i) for i in "abc"]
print(l)  # [97, 98, 99]

1 增加测试

# 输出0-5的偶数
# 通过filter实现
lf = list(filter(lambda x:x %2 == 0, range(5)))
print(lf)  # [0, 2, 4]
# 通过列表解析实现
ll = [x for x in range(5) if x % 2 == 0]
print(ll)  # [0, 2, 4]


2 列表解析循环嵌套

l = [(x, y) for x in range(3) for y in range(2)]
print(l)  # [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

# 嵌套的 for 循环中附加if
l = [(x, y) for x in range(4) if x % 2 == 0 for y in range(2) if y % 2 == 1]
print(l)  # [(0, 1), (2, 1)]

 

二、迭代器

    递归:在函数定义中使用函数自身的方法。(A调用A)
    迭代:利用变量的原值推算处变量的一个新值。(A不停调用B)

1、概念

    迭代器,被用于迭代的对象。利用变量的原值推算处变量的一个新值。(A不停调用B)

2、为什么要有迭代器?什么是可迭代对象?什么是迭代器对象?

   对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器

   什么是可迭代对象?
   可迭代对象指的是内置有 __iter__ 方法的对象,即 obj.__iter__, 如下

"python".__iter__()
(1,2,).__iter__()
{1,2}.__iter__()
[1,2].__iter__()
{"a": 1}.__iter__()
open("test.txt").__iter__()

    什么是迭代器对象?
    可迭代对象执行 obj.__iter__()得到的结果就是迭代器对象;
    而迭代器对象指的是既内置有__iter__ 有内置有 __next__ 方法的对象。

 #文件类型的迭代器对象
 open("test.txt").__iter__()
 open("test.txt").__next__()

注意:迭代器对象是可迭代对象;可迭代对象不一定是迭代器对象。


3、迭代器对象的使用

dic = {"a": 1, "b": 2}
iter_dic = dic.__iter__()  # 得到字典的迭代器对象,该迭代器对象既有 _iter__ 又有 __next__
print(iter_dic is iter_dic.__iter__())  # True ,迭代器调用 __iter__ 得到的对象还是本身

print(iter_dic.__next__())  # a
print(iter_dic.__next__())  # b
# print(iter_dic.__next__())  # StopIteration 抛出异常

4、for 循环调用迭代器

    for循环的工作原理:
    #1 执行in后面对象的dic.__iter__() 方法,得到一个迭代器对象 iter_dic
    #2 执行next(iter_dic), 将得到的值赋值给k,然后执行循环体代码
    #3 重复过程2,直到捕抓到异常 StopIteration,结束循环

dic = {"a": 1, "b": 2}
for k in dic:
    print(dic[k])
# 结果:
#     1
#     2

5、迭代器的优缺点

    优点:
        提供一种统一的、不依赖于索引的迭代方式
        惰性计算,节省内存
    缺点:
        无法获取长度(只有next完毕才知道到底几个值)
        一次性、只能往后走,不能回退

 

二、生成器函数

1、什么是生成器函数

    在Python中使用了 yield 的函数被称为生成器函数(generator)。跟普通函数不同的是,生成器函数是一个返回生成器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
    在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
    调用一个生成器函数,返回的是一个 generator 对象。

# 定义一个生成器函数
def gensquares(N):
    for i in range(N):
        yield i ** 2

# 调用生成器函数
# for i in gensquares(5):
#     print(i, end=" : ")  # 0 : 1 : 4 : 9 : 16 :
#     print()

# 通过生成器函数获取生成器对象
# 生成器对象有一个 __next__ 方法,可以开始这个函数,或者从它上次yield值后的地方恢复执行,
# 在产生一系列值后,再次调用将抛出 StopIteration 异常

x = gensquares(3)
print(x)  # <generator object gensquares at 0x00000233E21105E8>
# print(x.__next__())  # 0
# print(x.__next__())  # 2
# print(x.__next__())  # 4
# print(x.__next__()) # StopIteration

 通过 yield 实现斐波那契数列

def fibonacci(n):
    a, b, counter = 0, 1, 0
    while True:
        if(counter > n):
            return
        yield a
        a, b = b, a + b
        counter += 1

f = fibonacci(10)
print(dir(f))  # [......, 'close', 'send', 'throw']
while True:
    try:
        print(next(f), end=" ")
    except StopIteration:
        print("退出")  # 0 1 1 2 3 5 8 13 21 34 55 退出
        break

2、send() 方法

通过调用 next() 或 __next__() 方法,可以实现从外界控制生成器的执行。
    除此之外,通过send() 方法,还可以向生成器中传值,send() 方法可以带一个参数,也可以不带任何参数(用None 表示)。
    其中,当使用不带参数的 send() 方法时,它和 next() 函数的功能完全相同。
    注意,虽然 send(None) 的功能是 next() 完全相同,但更推荐使用 next(),不推荐使用 send(None)
    注意,带参数的 send(value) 无法启动执行生成器函数。也就是说,程序中第一次使用生成器调用 next() 或者 send() 函数时,不能使用带参数的 send() 函数。

def intNum():
    print("开始执行")
    for i in range(5):
        yield i
        print("继续执行")

num = intNum()
print(num.send(None))
print(num.send(None))
# 结果:
#     开始执行
#     0
#     继续执行
#     1

   这里重点讲解一些参数的 send(value) 的用法,其具备 next() 函数的部分功能,即将暂停在 yield 语句处的程序继续执行,
    但与此同时,该函数还会将 value 值作为 yield 语句返回值赋值给接收者。

def getStr():
    value1 = yield "string 1"
    value2 = yield value1
    yield value2

g = getStr()
print(g.send(None))
print(g.send("第二次获取结果"))
print(g.send("第三次获取结果"))
# 结果:
#     string 1
#     第二次获取结果
#     第三次获取结果

分析一下此程序的执行流程
1) 首先,构建生成器函数,并利用器创建生成器(对象)g 。

2) 使用生成器 g 调用无参的 send() 函数,其功能和 next() 函数完全相同,因此开始执行生成器函数,即执行到第一个 yield "string 1" 语句,该语句会返回 "string 1" 字符串,然后程序停止到此处(注意,此时还未执行对 value1 的赋值操作)。

3) 下面开始使用生成器 g 调用有参的 send() 函数,首先它会将暂停的程序开启,同时还会将其参数“第二次获取结果”赋值给当前 yield 语句的接收者,也就是 value1 变量。程序一直执行完 yield value1 再次暂停,因此会输出“第二次获取结果”。

4) 最后依旧是调用有参的 send() 函数,同样它会启动餐厅的程序,同时将参数“第三次获取结果”传给 value2,然后执行完 yield value2 后(输出 第三次获取结果),程序执行再次暂停。

因此,该程序的执行结果为:
string 1
第二次获取结果
第三次获取结果

3、close() 方法

    当程序在生成器函数中遇到 yield 语句暂停运行时,此时如果调用 close() 方法, 会阻止生成器函数继续执行,
    该函数会在程序停止运行的位置抛出 GeneratorExit 异常
    注意,虽然通过捕获 GeneratorExit 异常,可以继续执行生成器函数中剩余的代码,带这部分代码中不能再包含 yield 语句,否则程序会抛出 RuntimeError 异常
    另外,生成器函数一旦使用 close() 函数停止运行,后续将无法再调用 next() 函数或者 __next__() 方法启动执行,否则会抛出 StopIteration 异常。

def getStr1():
    try:
        yield "string 11"
    except GeneratorExit:
        print("捕获到 GeneratorExit")

g1 = getStr1()
print(next(g1))
g1.close()

# 结果:
#     string 11
#     捕获到 GeneratorExit

4、throw() 方法

    生成器 throw() 方法的功能是,在生成器函数执行暂停处,抛出一个指定的异常,之后程序会继续执行生成器函数后续的代码,直到遇到下一个yield 语句。
    注意,如果到剩余代码执行完毕没有遇到下一个 yield 语句,则程序会抛出 StopIteration 异常。

def getStr2():
    try:
        yield "string 22"
        print("继续执行")  # 下面调用时这里没有执行
    except ValueError:
        print("捕获到 ValueError")

g2 = getStr2()
print(next(g2))
g2.throw(ValueError)
print("再次调用-----------》")

# 结果:
#     string 22
#     捕获到 ValueError
#         exec(compile(contents+"\n", file, 'exec'), glob, loc)
#       File "D:/018_iterator_generator.py", line 244, in <module>
#         g2.throw(ValueError)
#     StopIteration

 显然,一开始生成器函数在 yield "string 22" 处暂停执行,当执行 throw() 方法时,它会先抛出 ValueError 异常,然后继续执行后续代码找到下一个 yield 语句,该程序中由于后续不再有 yield 语句,因此程序执行到最后,会抛出一个 StopIteration 异常。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的迭代器生成器是一种基于惰性计算的概念,它们可以有效地处理大量的数据或者无限序列。下面我将分别介绍迭代器生成器迭代器(Iterator)是一个实现了迭代协议(Iterator Protocol)的对象。通过调用内置函数 `iter()` 可以将可迭代对象转换为迭代器迭代器对象可以使用内置函数 `next()` 来逐个访问数据元素,直到没有更多的元素可供访问时,会引发 `StopIteration` 异常。例如,可以使用迭代器来遍历列表、元组、集合等容器类型的数据。 生成器(Generator)则是一种特殊的迭代器。它不需要显式地实现迭代协议,而是通过函数中的 `yield` 关键字来实现惰性计算。生成器函数在每次调用时返回一个值,并在下一次调用时从上一次离开的位置继续执行。这样可以节省大量的内存空间,并且提高程序的效率。生成器函数定义时使用 `def` 关键字,并包含至少一个 `yield` 关键字。 下面是一个简单的示例代码,演示了如何使用迭代器生成器: ```python # 使用迭代器遍历列表 my_list = [1, 2, 3, 4, 5] my_iter = iter(my_list) while True: try: item = next(my_iter) print(item) except StopIteration: break # 使用生成器生成斐波那契数列 def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b fib = fibonacci() for i in range(10): print(next(fib)) ``` 希望以上解释能够帮助你理解迭代器生成器的概念。如果有任何进一步的问题,请随时提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值