RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 802580
Accepted
pynista
pynista
Asked:2020-03-21 20:39:51 +0000 UTC2020-03-21 20:39:51 +0000 UTC 2020-03-21 20:39:51 +0000 UTC

为什么迭代器不按我想要的方式返回元素?

  • 772

编码

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”

python
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    Sergey Gornostaev
    2020-03-21T20:57:15Z2020-03-21T20:57:15Z

    因为该方法__next__应该返回迭代的当前值,并且您正在返回一个新的生成器。

    有两种方法可以解决这个问题。首先,不是将自身作为迭代器返回,而是作为生成器返回:

    def __iter__(self):
        for item in self.cities:
            yield item
    

    其次,控制你的状态,作为一个迭代器应该:

    class CitiesManager(object):
        ...
    
        def __iter__(self):
            """Возвратить себя как объект итератора."""
            self._item_index = -1
            return self
    
        def __next__(self):
            """Получить следующий элемент """
            self._item_index += 1
            if len(self.cities) <= self._item_index:
                raise StopIteration
            return self.cities[self._item_index]
    

    更新:正如@AndrioSkur 正确指出的那样,一个更正确的选择是__iter__每次调用该方法时都返回一个新的迭代器。

    class CitiesManagerIter(object):
        def __init__(self, cmanager):
            self.cmanager = cmanager
            self.__current_index = -1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            """Получить следующий элемент """
            self.__current_index += 1
            if len(self.cmanager.cities) <= self.__current_index:
                raise StopIteration
            return self.cmanager.cities[self.__current_index]
    
    
    class CitiesManager(object):
        ...
    
        def __iter__(self):
            """Возвратить объект итератора."""
            return CitiesManagerIter(self)
    
    • 3
  2. jfs
    2020-03-22T15:43:38Z2020-03-22T15:43:38Z

    为了使迭代工作,从问题中的代码中删除不兼容或损坏的__iter__方法就足够了。__next__

    __getitem__这两种方法的存在__len__表明您要创建一个序列(Sequence)而不是迭代器(__next__该方法返回(return)下一个值(如果有)或抛出StopIteration异常(如果没有),__iter__返回self迭代器)。

    您可以多次查看相同的序列。您可以通过索引从序列中获取单个元素:

    >>> R = range(3)
    >>> print(*R)
    0 1 2
    >>> print(*R)
    0 1 2
    >>> R[0]
    0
    

    *(星号)和**双星号在Python中是什么意思?

    一个迭代器只能被遍历一次。当元素用完并且迭代器已经抛出了一个 StopIteration 时,它会继续抛出一个 StopIteration(表示迭代结束):

    >>> iterator = iter(range(3))
    >>> print(*iterator)
    0 1 2
    >>> print(*iterator)
    
    >>> iterator[0]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'range_iterator' object is not subscriptable
    'range_iterator' object is not subscriptable
    

    第二个print只打印一个新行,因为第一个print 从迭代器中获取了所有元素。与序列不同,迭代器不支持索引。

    1)我想把这个类作为很多城市的容器,并给这个类添加其他功能,比如按人口过滤等。

    在 Python 中,如果您有一个想要按某些标准过滤的序列,则没有必要创建一个类(如果您在类名中看到 Manager 一词,这是一个很好的理由来考虑是否需要这个类全部)。例如,给定具有给定名称和纬度的城市列表:

    from collections import namedtuple
    
    City = namedtuple('City', 'name latitude')
    cities = [
        City('Петрозаводск', 61.77), 
        City('Хельсинки', 60.17),
        City('Санкт-Петербург', 59.95)
    ]
    

    在这个城市列表中很容易找到最北端的城市:

    northernmost_city = max(cities, key=lambda city: city.latitude)
    

    或者如果你想按字母顺序打印城市名称,也不需要创建一个新类:

    for city in sorted(cities):
        print(city.name)
    

    结论:

    Петрозаводск
    Санкт-Петербург
    Хельсинки
    

    2)我想很好地理解迭代器是如何工作的

    如果要创建迭代器,则从问题中的代码中删除方法 __getitem__,并返回__len__方法中的下一个值。__next__例如,这是一个无限迭代器:

    class Ones:
        def __iter__(self):
            return self
        def __next__(self):
            return 1
    

    例子:

    >>> from itertools import islice
    >>> print(*islice(Ones(), 10))
    1 1 1 1 1 1 1 1 1 1
    

    如果您希望迭代器用完,那么您应该抛出 StopIteration (并在后续调用中继续抛出):

    class EmptyIterator:
        def __iter__(self):
            return self
        def __next__(self):
            raise StopIteration
    

    该类定义了一个空迭代器(没有元素,立即抛出 StopIteration):

    >>> print(*EmptyIterator())
    
    >>>
    

    结合前两个迭代器示例,我们可以在纯 Python 中为列表定义迭代器模拟:

    class ListIterator:
        def __init__(self, lst):
            self.lst = lst
            self.i = 0
        def __iter__(self):
            return self
        def __next__(self):
            if self.i < len(self.lst):
                item = lst[self.i]
            else:
                raise StopIteration
            self.i += 1
            return item
    

    例子:

    >>> lst = [1, 2, 3]
    >>> it = ListIterator(lst)
    >>> print(*it)
    1 2 3
    >>> print(*it)
    
    >>> print(*lst)
    1 2 3
    

    可以看出,第一次遍历后,迭代器中的元素都结束了(第二次print只打印了一个新行),这对原始列表没有任何影响。相反,在迭代器遍历期间更改列表会影响返回的内容:两个 for 循环之间有什么区别:在列表遍历期间删除元素时。

    在答案中查看更多示例和链接(尤其是iter()):Differences between for and while loops。

    • 2
  3. MarianD
    2020-03-21T21:05:13Z2020-03-21T21:05:13Z

    首先,__next__(self)一个正常的功能,这意味着它想要return,没有yield。

    其次,迭代器必须在您的情况下结束,这意味着该方法__next__(self)必须在某个时间抛出异常StopIteration。

    因此,您的代码在 2 个地方(请参阅其中的 2 条评论)进行小幅改动后可能是这样的:

    class CitiesManager(object):
        """Класс, содержащий функциональность работы с городами."""
    
        def __init__(self, cities):
            self.cities = cities
            self.i      = -1                        // Добавлено
    
        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):                         // Изменено содержание метода
            """Получить следующий элемент """
            self.i += 1
            if self.i < len(self.cities):
                return self.cities[self.i]
            else:
                self.i = -1
                raise StopIteration
    
    cities = ['Петрозаводск', 'Хельсинки', 'Санкт-Петербург']
    north_cities = CitiesManager(cities)
    
    
    for city in north_cities:
        print(city)
    
    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5