47.md 6.4 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4
# Python 迭代器

> 原文: [https://www.programiz.com/python-programming/iterator](https://www.programiz.com/python-programming/iterator)

W
wizardforcel 已提交
5
#### 迭代器是可以迭代的对象。 在本教程中,您将学习迭代器如何工作以及如何使用`__iter__`和`__next__`方法构建自己的迭代器。
W
wizardforcel 已提交
6 7 8 9 10

## Python 中的迭代器

迭代器在 Python 中无处不在。 它们在`for`循环,理解力,生成器等中优雅地实现,但隐藏在清晰的视野中。

W
wizardforcel 已提交
11
Python 中的迭代器只是可以对其进行迭代的[对象](/python-programming/class)。 一个将返回数据的对象,一次返回一个元素。
W
wizardforcel 已提交
12 13 14

从技术上讲,Python **迭代器对象**必须实现两个特殊方法`__iter__()``__next__()`,统称为**迭代器协议**

W
wizardforcel 已提交
15
如果我们可以从中获得一个迭代器,则该对象称为**可迭代对象**。 Python 中大多数内置容器都是可迭代的,例如:[列表](/python-programming/list)[元组](/python-programming/tuple)[字符串](/python-programming/string)等。
W
wizardforcel 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

`iter()`函数(依次调用`__iter__()`方法)从它们返回一个迭代器。

* * *

## 通过迭代器进行迭代

我们使用`next()`函数手动迭代迭代器的所有项目。 当我们到达末尾并且没有更多数据要返回时,它将引发`StopIteration`异常。 以下是一个示例。

```py
# define a list
my_list = [4, 7, 0, 3]

# get an iterator using iter()
my_iter = iter(my_list)

# iterate through it using next()

# Output: 4
print(next(my_iter))

# Output: 7
print(next(my_iter))

# next(obj) is same as obj.__next__()

# Output: 0
print(my_iter.__next__())

# Output: 3
print(my_iter.__next__())

# This will raise error, no items left
next(my_iter)
```

**输出**

```py
4
7
0
3
Traceback (most recent call last):
  File "<string>", line 24, in <module>
    next(my_iter)
StopIteration
```

W
wizardforcel 已提交
65
一种更优雅的自动迭代方式是[`for`循环](/python-programming/for-loop)。 使用此方法,我们可以迭代可以返回迭代器的任何对象,例如列表,字符串,文件等。
W
wizardforcel 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78

```py
>>> for element in my_list:
...     print(element)
...     
4
7
0
3
```

* * *

W
wizardforcel 已提交
79
## 迭代器和`for`循环
W
wizardforcel 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

如上例所示,`for`循环能够自动迭代列表。

实际上,`for`循环可以迭代任何可迭代的对象。 让我们仔细看看`for`循环是如何在 Python 中实际实现的。

```py
for element in iterable:
    # do something with element
```

实际上是实现为。

```py
# create an iterator object from that iterable
iter_obj = iter(iterable)

# infinite loop
while True:
    try:
        # get the next item
        element = next(iter_obj)
        # do something with element
    except StopIteration:
        # if StopIteration is raised, break from loop
        break
```

因此,在内部,`for`循环通过在可迭代对象上调用`iter()`创建了迭代器对象`iter_obj`

W
wizardforcel 已提交
109
具有讽刺意味的是,这个`for`循环实际上是一个无限[`while`循环](/python-programming/while-loop)
W
wizardforcel 已提交
110

W
wizardforcel 已提交
111
在循环内部,它调用`next()`获取下一个元素,并使用该值执行`for`循环的主体。 所有物品耗尽后,`StopIteration`抛出,内部被卡住,循环结束。 请注意,任何其他类型的异常都将通过。
W
wizardforcel 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

* * *

## 构建自定义迭代器

在 Python 中从头开始构建迭代器很容易。 我们只需要实现`__iter__()``__next__()`方法。

`__iter__()`方法返回迭代器对象本身。 如果需要,可以执行一些初始化。

`__next__()`方法必须返回序列中的下一项。 在到达末尾以及随后的调用中,它必须提高`StopIteration`

在这里,我们显示一个示例,该示例将在每次迭代中为我们提供下一个 2 的幂。 幂指数从零开始一直到用户设置的数字。

```py
class PowTwo:
    """Class to implement an iterator
    of powers of two"""

    def __init__(self, max=0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 ** self.n
            self.n += 1
            return result
        else:
            raise StopIteration

# create an object
numbers = PowTwo(3)

# create an iterable from the object
i = iter(numbers)

# Using next to get to the next iterator element
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
```

W
wizardforcel 已提交
159
**输出**
W
wizardforcel 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247

```py
1
2
4
8
Traceback (most recent call last):
  File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module>
    print(next(i))
  File "<string>", line 18, in __next__
    raise StopIteration
StopIteration
```

我们还可以使用`for`循环来迭代迭代器类。

```py
>>> for i in PowTwo(5):
...     print(i)
...     
1
2
4
8
16
32
```

* * *

## Python 无限迭代器

不必耗尽迭代器对象中的项目。 可以有无限迭代器(永无止境)。 处理此类迭代器时必须小心。

这是一个演示无限迭代器的简单示例。

可以使用两个参数来调用[内置函数](/python-programming/built-in-function) `iter()`函数,其中第一个参数必须是可调用的对象(函数),第二个参数是前哨。 迭代器将调用此函数,直到返回的值等于哨兵。

```py
>>> int()
0

>>> inf = iter(int,1)
>>> next(inf)
0
>>> next(inf)
0
```

我们可以看到`int()`函数始终返回 0。因此,将其传递为`iter(int,1)`将返回一个迭代器,该迭代器将调用`int()`,直到返回的值等于 1。这永远不会发生,并且会得到一个无限的迭代器。

我们还可以构建自己的无限迭代器。 理论上,以下迭代器将返回所有奇数。

```py
class InfIter:
    """Infinite iterator to return all
        odd numbers"""

    def __iter__(self):
        self.num = 1
        return self

    def __next__(self):
        num = self.num
        self.num += 2
        return num
```

样本运行如下。

```py
>>> a = iter(InfIter())
>>> next(a)
1
>>> next(a)
3
>>> next(a)
5
>>> next(a)
7
```

等等...

在这些类型的无限迭代器上进行迭代时,请小心包含终止条件。

使用迭代器的优点是节省了资源。 如上图所示,我们无需将整个数字系统存储在内存中就可以获得所有奇数。 从理论上讲,我们可以在有限内存中包含无限项。

W
wizardforcel 已提交
248
有一种在 Python 中创建迭代器的简便方法。 要了解更多信息,请访问:[使用`yield`的 Python 生成器](/python-programming/generator)