何时使用__iter __()和iter()?

Rue*_*hri 4 python

假设我有一个实现__iter__()函数的类,首选使用iter(obj)还是obj.__iter__()直接调用?除了使用magic函数少输入5个字符之外,还有什么真正的区别?

相比之下:对于next()__next__()我可以看到在magic函数中具有默认值的优点。

Dun*_*nes 5

区别主要在于便利。它减少了打字,减少了符号的读取,因此读取速度更快。然而,各种内置函数(例如iterlen等),通常做一个小小的型早期检查,以捕获错误。如果您编写了一个客户__iter__方法并返回 2,则调用obj.__iter__()不会捕获该方法,但是iter(obj)会引发类型错误。例如。

>>> class X:
    def __iter__(self):
        return 2

>>> x = X()
>>> x.__iter__()
2
>>> iter(x)
Traceback (most recent call last):
  File "<pyshell#37>", line 1, in <module>
    iter(x)
TypeError: iter() returned non-iterator of type 'int'
Run Code Online (Sandbox Code Playgroud)

iter还为no的对象实现了迭代器协议__iter__,但确实实现了序列协议。也就是说,它们具有一种__getitem__方法,该方法实现从索引0开始的序列,并为不在范围内的索引引发IndexError。这是python的较旧功能,并不是真正应该使用的新代码。例如。

>>> class Y:
    def __getitem__(self, index):
        if 0 <= index < 5:
            return index ** 2
        else:
            raise IndexError(index)

>>> list(iter(Y()))  # iter not strictly needed here
[0, 1, 4, 9, 16]
Run Code Online (Sandbox Code Playgroud)

什么时候应该使用__iter__?这可能与无关紧要__iter__,但是如果您需要访问父类使用的方法的实现,则最好以样式super().__<dunder_method>__()(使用Python 3样式的超级用法)调用此类方法。例如。

>>> class BizzareList(list):
    def __iter__(self):
        for item in super().__iter__():
            yield item * 10

>>> l = BizzareList(range(5))
>>> l  # normal access
[0, 1, 2, 3, 4]
>>> l[0]  # also normal access
0
>>> tuple(iter(l))  # iter not strictly needed here
(0, 10, 20, 30, 40)
Run Code Online (Sandbox Code Playgroud)