__iter__中__getitem__的等效代码

Sea*_*hot 0 python iterator python-3.x

我试图__iter__在Python 3中更多地了解.出于某些原因__getitem__,我更好地理解__iter__.我想我不知道怎么没有得到相应的下一个实现__iter__.

我有以下代码:

class Item:
    def __getitem__(self,pos):
        return range(0,30,10)[pos]

item1= Item()
print (f[1]) # 10
for i in item1:
   print (i) # 0 10 20
Run Code Online (Sandbox Code Playgroud)

我理解上面的代码,但是又如何使用__iter__和编写等效代码__next__()

class Item:
   def __iter__(self):
      return self
      #Lost here
   def __next__(self,pos):
      #Lost here
Run Code Online (Sandbox Code Playgroud)

我理解当python看到一个__getitem__方法时,它会尝试通过调用带有整数索引的方法来迭代该对象0.

Jim*_*ard 5

一般来说,一个非常好的方法是通过值__iter__生成一个生成器yield.这可能不太直观,但它是直截了当的; 您只需回收所需的结果,__next__然后自动为您提供:

class Item:
   def __iter__(self):
      for item in range(0, 30, 10):
          yield item
Run Code Online (Sandbox Code Playgroud)

这只是使用yield获得所需效果的力量,当Python调用__iter__你的对象时,它期望一个iterator(即一个支持__next__调用的对象),一个生成器就是这样,生成你的生成器函数中定义的每个项目(即__iter__在此case)何时__next__被调用:

>>> i = iter(Item())    
>>> print(i)  # generator, supports __next__
<generator object __iter__ at 0x7f6aeaf9e6d0>
>>> next(i)
0
>>> next(i)
10
>>> next(i)
20
Run Code Online (Sandbox Code Playgroud)

现在你得到的效果与之相同__getitem__.区别在于没有index传入,你必须手动循环它以产生结果:

>>> for i in Item():
...    print(i)    
0
10
20
Run Code Online (Sandbox Code Playgroud)

除此之外,还有另外两种方法可用于创建支持迭代的对象.

一次循环:使项目成为迭代器

Item通过定义一个迭代器__next__和返回self__iter__在这种情况下,因为你不使用yield__iter__方法返回self__next__处理返回值的逻辑:

class Item:

   def __init__(self):
      self.val = 0

   def __iter__(self):
      return self

   def __next__(self):
      if self.val > 2: raise StopIteration
      res = range(0, 30, 10)[self.val]
      self.val += 1
      return res
Run Code Online (Sandbox Code Playgroud)

这也使用辅助val来从范围中获取结果并检查我们是否仍应该迭代(如果没有,我们提出StopIteration):

>>> for i in Item():
...    print(i)
0
10
20
Run Code Online (Sandbox Code Playgroud)

这种方法的问题在于它是一次性骑行,在迭代一次之后,self.val3和迭代不能再次执行.(使用yield解决此问题).(是的,你可以去设置val为0,但这只是偷偷摸摸.)

循环多次:创建自定义迭代器对象.

第二种方法是专门为您的Item类使用自定义迭代器对象并从而返回它Item.__iter__而不是self:

class Item:
    def __iter__(self):
        return IterItem()


class IterItem:
   def __init__(self):
      self.val = 0
   def __iter__(self):
      return self
   def __next__(self):
      if self.val > 2: raise StopIteration
      res = range(0, 30, 10)[self.val]
      self.val += 1
      return res
Run Code Online (Sandbox Code Playgroud)

现在,每次迭代时都会提供一个新的自定义迭代器,您可以支持Item对象的多次迭代.