python 迭代器与生成器即迭代协议的特别说明

python 中抽象程度更高,直接在语言层面支持对容器进行迭代。C++ 中在泛型算法和容器之间还需要借助中间层迭代器来粘合。

可迭代的是两类对象:

1、包含 __iter__ 方法的。

2、包含 __getitem__ 方法的。比如 str 对象就没有 __iter__ 方法,但是一样能够迭代。

另外,判断是否只能迭代一次的:

iter(obj) == obj

相等表示 obj 是自身的迭代器,所以只能迭代一次。

不等表示每次跌倒时,实际都是生成一个临时对象来操作,所以能够迭代多次。


生成器还包含三个特殊的方法:

send(), close(), throw().

receive = yield value
...
g.send(1)

调用 send  方法之后,也是在进入生成器并在 yield 停止,返回 yiled 后边的表达式,这一点同 next 函数一样。

不同之处在于,在send 为下一次进入生成器时,传入一个值。代码片段中 receive 是在下一次进入生成器时赋值为send传入的值。

下一次生成器再执行,第一条语句是 receive = 1

close() 方法用来关闭生成器,之后再拿关闭之后的生成来迭代直接抛出 StopIteration 异常。

throw() 方法用来显示的再进入到迭代器时抛出一个异常,如果该异常不能被捕获,程序直接结束;能捕获,则关注捕获的地方。如果捕获的地方在生成器的内部,生成器有效;如果是生成器外部捕获,相当于由非 yield 跳出的生成器,生成器不能再迭代了。

总结:非yield的跳出,如 return,break 等跳转语句或抛出异常E,在跳出了之后,立即抛出 StopIteration 或者异常E。


有了迭代协议,可以更方便的表达类似的概念,而不用关注底层的实现(抽象的好处,有选择性的忽略,降低问题的复杂度)。

1、函数的可变参数包,表示调用时,最终打包成 tuple 元祖。

l = list(range(3))

s = "hello"

d = dict(x = 1, y = 2, z = 3)

def gen():
    yield 1
    yield 2
    yield 3

def func(*a):
    print(type(a))
    print(a)

func(*d)    #字典
func(*gen())   #生成器
func(*l)   #列表
func(*s)  #字符串

输出如下,#调用时,* + 可迭代对象:表示将可调用对象解包成位置参数。不论参数是普通容器还是生成器,只要是可迭代的,皆可以在调用时解包。匹配掉前边的位置参数和已命名的参数,剩下的打包进 tuple 作为可变参数。

<class 'tuple'>
('x', 'y', 'z')
<class 'tuple'>
(1, 2, 3)
<class 'tuple'>
(0, 1, 2)
<class 'tuple'>
('h', 'e', 'l', 'l', 'o')

2、关键字参数,表示调用时,最终打包成 dict 字典。

命名参数这里指的是调用时,按照 参数名 = value 的形成进行调用,且参数名称出现在函数定义的列表中的参数。如下边的函数 fund 中的参数 y,在字典解包时,传入的值为2.匹配掉已命名的关键字参数,剩下的打包进dict.

d = dict(x = 1, y = 2, z = 3)

def fund(y = 0, **a):
    print(type(a))
    print(a)

fund(**d)    #字典

输出如下:
没啥好说的,** + 字典表示字典解包成 key = value 的关键字参数包(键为 "key" 字符串)。 'y' 匹配给了命名参数。

<class 'dict'>
{'x': 1, 'z': 3}
3、 聚合赋值,表示赋值左边的带 * 对象打包成 list 列表。

a = 1
b = 2
c = 3

def gen():
    yield 1
    yield 2
    yield 3

x, *y = a, b, c   #a, b, c 等价于 (a, b, c)是个元祖
print(type(x),x)
print(type(y), y)

x, *y = dict(a = 1, b = 2, c = 3)
print(type(x),x)
print(type(y), y)

x, *y = gen()
print(type(x),x)
print(type(y), y)
输出如下:

<class 'int'> 1
<class 'list'> [2, 3]
<class 'str'> a
<class 'list'> ['b', 'c']
<class 'int'> 1
<class 'list'> [2, 3]
同1一样,建立在迭代协议之上,只要赋值右边是可迭代的,赋值左边的 *y 表示按照 list 列表打包。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值