编码
class CitiesManager(object):
"""Класс, содержащий функциональность работы с городами."""
def __init__(self, cities):
self.cities = cities
def __getitem__(self, item: int):
"""Получить элемент по индексу.
Args:
item (int): индекс элемента для получения в операциях среза.
"""
return self.cities[item]
def __len__(self):
return len(self.cities)
def __iter__(self):
"""Возвратить себя как объект итератора."""
return self
def __next__(self):
"""Получить следующий элемент """
for item in self.cities:
yield item
cities = ['Петрозаводск', 'Хельсинки', 'Санкт-Петербург']
north_cities = CitiesManager(cities)
for city in north_cities:
print(city)
输出如下内容:
<generator object __next__ at 0x7f13de432d58>
<generator object __next__ at 0x7f13de432c50>
<generator object __next__ at 0x7f13de432d58>
<generator object __next__ at 0x7f13de432c50>
<generator object __next__ at 0x7f13de432d58>
为什么?我希望它显示字符串“Petrozavodsk”、“Helsinki”、“St. Petersburg”
因为该方法
__next__应该返回迭代的当前值,并且您正在返回一个新的生成器。有两种方法可以解决这个问题。首先,不是将自身作为迭代器返回,而是作为生成器返回:
其次,控制你的状态,作为一个迭代器应该:
更新:正如@AndrioSkur 正确指出的那样,一个更正确的选择是
__iter__每次调用该方法时都返回一个新的迭代器。为了使迭代工作,从问题中的代码中删除不兼容或损坏的
__iter__方法就足够了。__next____getitem__这两种方法的存在__len__表明您要创建一个序列(Sequence)而不是迭代器(__next__该方法返回(return)下一个值(如果有)或抛出StopIteration异常(如果没有),__iter__返回self迭代器)。您可以多次查看相同的序列。您可以通过索引从序列中获取单个元素:
*(星号)和**双星号在Python中是什么意思?
一个迭代器只能被遍历一次。当元素用完并且迭代器已经抛出了一个 StopIteration 时,它会继续抛出一个 StopIteration(表示迭代结束):
第二个
print只打印一个新行,因为第一个print从迭代器中获取了所有元素。与序列不同,迭代器不支持索引。在 Python 中,如果您有一个想要按某些标准过滤的序列,则没有必要创建一个类(如果您在类名中看到 Manager 一词,这是一个很好的理由来考虑是否需要这个类全部)。例如,给定具有给定名称和纬度的城市列表:
在这个城市列表中很容易找到最北端的城市:
或者如果你想按字母顺序打印城市名称,也不需要创建一个新类:
结论:
如果要创建迭代器,则从问题中的代码中删除方法
__getitem__,并返回__len__方法中的下一个值。__next__例如,这是一个无限迭代器:例子:
如果您希望迭代器用完,那么您应该抛出 StopIteration (并在后续调用中继续抛出):
该类定义了一个空迭代器(没有元素,立即抛出 StopIteration):
结合前两个迭代器示例,我们可以在纯 Python 中为列表定义迭代器模拟:
例子:
可以看出,第一次遍历后,迭代器中的元素都结束了(第二次
print只打印了一个新行),这对原始列表没有任何影响。相反,在迭代器遍历期间更改列表会影响返回的内容:两个 for 循环之间有什么区别:在列表遍历期间删除元素时。在答案中查看更多示例和链接(尤其是
iter()):Differences between for and while loops。首先,
__next__(self)一个正常的功能,这意味着它想要return,没有yield。其次,迭代器必须在您的情况下结束,这意味着该方法
__next__(self)必须在某个时间抛出异常StopIteration。因此,您的代码在 2 个地方(请参阅其中的 2 条评论)进行小幅改动后可能是这样的: