[英]Confusions about python Iterators
我练习迭代器的次数越多,我就越会感到困惑。 我对对象和类很有信心(只有我们学到的知识,而没有学到继承),但是迭代器和生成器使我很困惑。 非常感谢您的帮助。
我有一些问题:
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)
__iter__
返回的self之后(也由next使用)为iterator类型,那么如何访问self.index
? 2)在下面的代码中,我试图遍历特定的事物,例如键或值或字典类中的项。 它抛出错误“迭代器”对象没有属性“索引”。 为什么self.index无法访问字典类的实例变量索引?
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)
我用很多注释重写了您的代码,以尝试解释示例(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)中的要求时,您可能会发现还有其他更改方式。
这只会回答您的第一个问题,并可能会帮助您解决问题2。
引用“ Fluent Python”(第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]
我基本上要做的是创建对可迭代调用的引用,并将其保存在self.iterable
。 现在,每次调用__next__
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__
返回实例本身,因为该类本身现在是可迭代的并且是迭代器(请记住:迭代器具有__next__
dunder方法,而可迭代的具有__iter__
dunder方法可返回迭代器)。
最后一个有趣的地方是,当调用这些dunder方法时。 实际上,在使用for in
语法时,它是以下语法糖:
a = Main()
## recreating the for in loop
itr = a.__iter__()
while True:
try:
print(itr.__next__())
except StopIteration:
break
您首先初始化迭代器,然后__next__
返回一个值,直到迭代器用尽。
编辑:
您真的应该再次阅读我的帖子。 分离迭代器不是一个好习惯。 只是为了演示它们在内部如何工作。 另外,请不要定义自己的dunder方法。 那会在某些时候破坏您的代码。 我已经在下面更正了您的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
那就是我想出的:
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.