可迭代对象、迭代器及可迭代元素解包(元组解包)

本文介绍了Python中的可迭代对象、迭代器的概念,并探讨了解包(元组解包)的用法。在参数传递中,*用于强制解包,使未解包的元素能够被接收。一个类通过实现`__iter__`和`__next__`方法成为可迭代对象,而`__getitem__`方法的实现也让类具备解包和迭代能力。虽然自定义类可能没有直接继承`Iterator`或`Iterable`,但通过属性检查仍然可以被视为它们的子类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

*的用法–解包和收集多余参数

# 平行赋值
a, *b, c = [1, 2, 3, 4] 
# a =1, b=[2, 3] , c=4
# a, *b, c = *[1, 2, 3, 4]  #错误的用法,右侧不能使用*

def f0(*a):
	print(a)
f0(1, 2, 3)
# (1, 2, 3)

def f1(a, b, c):
	print(a, b, c)
f1(*(1, 2, 3))
# 1, 2, 3

* 一个作用是收集多余的元素。平行赋值中,等号右侧默认解包,所以使用 * 号是多余的,会报错。
但是在参数传递中,参数是默认不解包的,因此可以用* 强制要求解包。

可迭代对象都支持解包
怎么定义可迭代对象,从鸭子类型来说,实现了 __iter__的类是可迭代的。该方法需要能够返回一个迭代器,用于迭代时元素的产生。因此迭代器负责生成值具体执行者, 迭代器除了实现 __iter__ 之外,还要实现__next__ 方法, 这两者分别对应于Python的内置函数,iter()构建生成器和next()产生一个值。
可以使用isinstance和issubclass检查类型

from collections.abc import Iterator, Iterable

class Myclass:
    def __next__(self):
        pass
    def __iter__(self):
        pass

myinstance = Myclass()
print(isinstance(myinstance, Iterator))
print(issubclass(Myclass, Iterator))

运行可以发现,Myclass并没有显示继承Iterator, Iterable,但是也能通过上述检查, 这似乎不合理。这是由于Iterator, Iterable实现了__subclasshook__。该方法是基于属性检查的,也就是说只要自定义类或者其父类实现了迭代器的两个方法就可以被认定为是其子类。

除了上述特点外,自定义的序列类型,即使没有实现上述两个特殊方法,也是可以解包和迭代的。
当解释器需要可迭代对象时,会默认调用iter(x)获得可迭代对象,该方法执行如下操作:
1、检查对象x是否实现了 __iter__, 如果有就调用它返回一个可迭代对象。
2、如果没有, 尝试调用__getitem__从序列头部开始创建一个可迭代对象。因此实现了__getitem__的类也是可以用来解包和迭代的。但是该类和其对象是通不过可迭代对象或者迭代器检查的, 因为没有实现 __iter__ ,__next__ 。
3、如果上述两步都失败了,就返回一个TypeError

参考:
Fluent Python chapter14, Chapter2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值