社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

关于python迭代器的困惑

lynxx • 4 年前 • 256 次点击  

我练习的迭代器越多,我就越困惑。我对对象和类很有信心(这是我们唯一学到的东西,不是学到的继承),但是迭代器和生成器把我的脑子搞得乱七八糟任何帮助都是非常感谢的。

我有几个问题:

1)代码如下:

class main():
    def __init__(self):
        self.items=[1,2,3,4,5,6,7]
        self.index= 0

    def __iter__(self):
        return self 

    def __next__(self):
        self.index+=1

        return self.items[self.index]

a = main()

for i in a:
    print(i)  
  1. 我们这里有两个人一个在init中,它指的是对象“a”,另一个由self返回。什么是真正的自我数据类型?它是main()类型还是迭代器类型?
  2. 类似于上面的问题-当我们给予 下一个 (self),我们给下一个(类型(a)的迭代器)什么self?
  3. 如果自己回来后 __iter__ (也被next使用)是迭代器类型,如何访问 self.index ?

2)在下面的代码中,我试图对dictionary类中的键、值或项等特定内容进行迭代。 它正在引发错误“iterator”对象没有“index”属性。 为什么self.index不能访问dictionary类的实例变量索引?

class Pair():
    def __init__(self, key ,value):
        self.key = key
        self.value = value

class Dictionary():
    def __init__(self):
        self.items =[]
        self.index = -1     ################## INDEX DEFINED HERE

    def __setitem__(self, key, value):
        for i in self.items:
            if i.key == key:
                i.value = value
                return
        self.items.append(Pair(key,value))

    def __keys__(self):
        return iterator(self, 'keys')

    def __values__(self):
        return iterator(self, 'values')

    def __items__(self):
        return iterator(self , 'items')

class iterator():
    def __init__(self, object, typo):
        self.typo = typo

    def __iter__(self):
        return self

    def __next__(self):
        if self.typo == 'keys': 
            self.index +=1  #################### ERROR
            if self.index >= len(self.items):
                raise StopIteration
            return self.items[self.index].keys

        ` # Similarly for keys and items as well`

collins = Dictionary()

collins['google'] = 'pixel'
collins['htc'] = 'M8'
collins['samsung'] = 'S9'


for i in collins.__keys__():
    print(i)
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/48913
 
256 次点击  
文章 [ 3 ]  |  最新文章 4 年前
lynxx
Reply   •   1 楼
lynxx    5 年前

我就是这么想的:

class Pair():
    def __init__(self, key, value):
        self.key = key
        self.value = value


class dictionary():
    def __init__(self):
        self.items = []

    def add(self, objects):
        self.items.append(objects)

    def __keys__(self):
        return iterator(self, 'keys')

    def __values__(self):
        return iterator(self, 'values')

class iterator():
    def __init__(self, to_be_iterated , over_what):
        self.to_be_iterated = to_be_iterated
        self.over_what = over_what


    def __iter__(self):
        self.index = -1
        return self

    def __next__(self):
        self.index += 1
        if self.over_what == 'keys':
            try:
                    return self.to_be_iterated.items[self.index].key
            except Exception:
                raise StopIteration

        elif self.over_what == 'values':
            try:
                    return self.to_be_iterated.items[self.index].value
            except Exception:
                raise StopIteration


collins = dictionary()

collins.add(Pair('up', 'above'))
collins.add(Pair('down', 'below'))

for i in collins.__keys__():
    print(i)

for i in collins.__values__():
    print(i)
DocDriven
Reply   •   2 楼
DocDriven    5 年前

这只回答了你的第一个问题,也许能帮助你解决问题2。

引用《流畅的蟒蛇》(第420页):

[…]对象实现 __iter__ 返回迭代器的方法是可迭代的。[…]

也就是说,你可以(理论上)这样做:

class Main:
    def __init__(self):
        self.items = list(range(1, 8))
        self.length = len(self.items)

    def __iter__(self):
        return MainIterator(self)

现在,但是 MainIterator 上课的样子迭代器只需要 __next__ 确定它返回的下一个值的dunder方法实现可能如下所示:

class MainIterator:
    def __init__(self, iterable):
        self.iterable = iterable
        self.index = 0

    def __next__(self):
        if self.index >= self.iterable.length:
            raise StopIteration

        self.index += 1
        return self.iterable.items[self.index - 1]

我主要做的是创建对调用iterable的引用并将其保存到 self.iterable 是的。现在每次 _下一个__ dunder方法被调用,它返回数组的一个元素,直到迭代器用完为止。这是通过提高 StopIteration 是的。

您不会经常看到这样的实现,因为这两个类通常合并为一个类。我只是想证明把两者分开是可能的。结果是@rbricheno已经发布了:

class Main:
    def __init__(self):
        self.items = list(range(1, 8))
        self.length = len(self.items)

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

    def __next__(self):
        if self.index >= self.length:
            raise StopIteration

        self.index += 1
        return self.items[self.index - 1]

不同的是 __init__ 返回实例本身,因为类本身现在是iterable和iterator(记住:iterator有 _下一个__ dunder方法,iterable有 _ ITER__ 返回迭代器的dunder方法)。

最后一个有趣的地方是,当这些dunder方法被调用时。实际上,当使用 for in 语法,它是语法糖,用于:

a = Main()

## recreating the for in loop

itr = a.__iter__()

while True:
    try:
        print(itr.__next__())
    except StopIteration:
        break

首先初始化迭代器,然后 _下一个__ 返回一个值,直到迭代器耗尽为止。

编辑:

你真的应该再读我的文章。分离迭代器不是很好的做法。只是为了演示它们是如何在内部工作的另外,请不要定义自己的邓德尔方法有时会破坏你的代码我已经更正了下面的dict类,但是我遍历了这对类,而不是它的组件。

class Pair:

    def __init__(self, key, value):
        self.key = key
        self.value = value

    ## you need this to display your class in a meaningful way
    def __repr__(self):
        return f'{__class__.__name__}({self.key}, {self.value})'

class Dictionary:

    def __init__(self):
        self.items = []
        self.length = len(self.items)

    def add(self, objects):
        self.items.append(objects)
        self.length += 1

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

    def __next__(self):
        if self.index >= self.length:
            raise StopIteration

        self.index += 1
        return self.items[self.index - 1]

a = Dictionary()

a.add(Pair('up', 'above'))
a.add(Pair('down', 'below'))

for i in a:
    print(i.key)
    print(i.value)

我的机器上的输出:

up
above
down
below
Rob Bricheno
Reply   •   3 楼
Rob Bricheno    5 年前

我用很多注释重写了您的代码,试图解释示例(1)中发生的事情。

class MainClass():
    def __init__(self):
        # The value 'self' always refers to the object we are currently working
        # on. In this case, we are instantiating a new object of class
        # MainClass, so self refers to that new object.
        # self.items is an instance variable called items within the object
        # referred to as self.
        self.items = [1, 2, 3, 4, 5, 6, 7]
        # We do not want to declare self.index here. This is a slightly subtle
        # point. If we declare index here, then it will only be set when we first
        # create an object of class MainClass. We actually want self.index to be
        # set to zero each time we iterate over the object, so we should set it
        # to zero in the __iter__(self) method.
        # self.index = 0

    def __iter__(self):
        # This is an instance method, which operates on the current instance of
        # MainClass (an object of class MainClass). This method is called when
        # we start iteration on an object, so as stated above, we'll set
        # self.index to zero.
        self.index = 0
        return self

    def __next__(self):
        # This is also an instance method, which operates on the current
        # instance of MainClass.
        if self.index < len(self.items):
            self.index += 1
            return self.items[self.index - 1]
        else:
            # This is how we know when to stop iterating.
            raise StopIteration()


a = MainClass()

# a is now an object of class MainClass
# Because we have implemented __iter__ and __next__ methods in MainClass,
# objects of class MainClass are iterable, so a is also iterable.

# When we say "for i in a" this is like shorthand for  saying "a.__iter__()"
# and then "i = a.__next__()" until we raise
# a StopIterationException

# Here we are iterating over the result of a.__iter__() until a.__next__()
# raises a StopIterationException
for i in a:
    # Here we are printing the value returned by a.__next__()
    print(i)

我认为这可能有助于您在转到(2)并仔细检查您对对象和类的了解之前回顾这一点我们在(2)中看到的第一个问题是 object 给你的 iterator 类,但不要将其存储在任何地方,以便以后无法访问它但是,当你更充分地理解(1)中的所有要求时,你可能会发现你有其他想要改变它的方法。