为什么 yield from inside __next__() return 生成器对象?
Why does a yield from inside __next__() return generator object?
我在 class 的 __next__()
函数中使用 yield
来 return 下一个值。但是它不会 return 下一个值,它 return 是生成器对象。
我正在努力更好地理解迭代器和 yield
。我可能做错了。
看看。
class MyString:
def __init__(self,s):
self.s=s
def __iter__(self):
return self
def __next__(self):
for i in range(len(self.s)):
yield(self.s[i])
r=MyString("abc")
i=iter(r)
print(next(i))
这个returns:
generator object __next__ at 0x032C05A0
next
在这种情况下几乎只是调用 __next__()
。在你的对象上调用 __next__
将启动生成器并 return 它(此时没有魔法)。
在这种情况下,您 可能 完全不定义 __next__
就可以逃脱:
class MyString:
def __init__(self,s):
self.s=s
def __iter__(self):
for i in range(len(self.s)):
yield(self.s[i])
# Or...
# for item in self.s:
# yield item
如果你想使用 __iter__
和 __next__
(定义一个 iterator rather than simply making an iterable),你可能想做这样的事情:
class MyString:
def __init__(self,s):
self.s = s
self._ix = None
def __iter__(self):
return self
def __next__(self):
if self._ix is None:
self._ix = 0
try:
item = self.s[self._ix]
except IndexError:
# Possibly reset `self._ix`?
raise StopIteration
self._ix += 1
return item
让我们来看看__next__
方法的目的。来自 the docs:
iterator.__next__()
Return the next item from the container. If there are no further items, raise the StopIteration exception.
现在让我们看看 yield
语句的作用。 the docs 的另一段摘录:
Using a yield expression in a function’s body causes that function to
be a generator
和
When a generator function is called, it returns an iterator known as a
generator.
现在比较 __next__
和 yield
:__next__
return 容器中的下一个项目 。但是包含 yield
关键字的函数 return 是一个迭代器 。因此,在 __next__
方法中使用 yield
会产生一个产生迭代器的迭代器。
如果您想使用 yield
使您的 class 可迭代,请在 __iter__
方法中执行:
class MyString:
def __init__(self, s):
self.s = s
def __iter__(self):
for s in self.s:
yield s
__iter__
方法应该 return 一个迭代器 - 而 yield
关键字使它做到这一点。
为了完整起见,下面是如何使用 __next__
方法实现迭代器。您必须跟踪迭代的状态,以及 return 相应的值。最简单的解决方案可能是每次调用 __next__
时增加一个索引:
class MyString:
def __init__(self,s):
self.s = s
self.index = -1
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index >= len(self.s):
raise StopIteration
return self.s[self.index]
据我所知,生成器函数只是 classes 和 next 函数的语法糖。示例:
>>> def f():
i = 0
while True:
i += 1
yield i
>>> x = f()
>>> x
<generator object f at 0x0000000000659938>
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> class g(object):
def __init__(self):
self.i = 0
def __next__(self):
self.i += 1
return self.i
>>> y = g()
>>> y
<__main__.g object at 0x000000000345D908>
>>> next(y)
1
>>> next(y)
2
>>> next(y)
3
事实上,我来这里是想看看是否有任何显着差异。有的话请喊一声。
所以,要回答这个问题,您拥有的是一个 class 和 __next__ 方法,returns 一个对象也有一个 __next__ 方法。因此,最简单的做法是用 return
替换 yield
并跟踪你走了多远,并记住在到达数组末尾时引发 StopIteration 。所以像:
class MyString:
def __init__(self,s):
self.s=s
self._i = -1
def __iter__(self):
return self
def __next__(self):
self._i += 1
if self._i >= len(self.s):
raise StopIteration
return self.s[self._i]
这可能是实现我认为您正在寻找的东西的最简单方法。
我在 class 的 __next__()
函数中使用 yield
来 return 下一个值。但是它不会 return 下一个值,它 return 是生成器对象。
我正在努力更好地理解迭代器和 yield
。我可能做错了。
看看。
class MyString:
def __init__(self,s):
self.s=s
def __iter__(self):
return self
def __next__(self):
for i in range(len(self.s)):
yield(self.s[i])
r=MyString("abc")
i=iter(r)
print(next(i))
这个returns:
generator object __next__ at 0x032C05A0
next
在这种情况下几乎只是调用 __next__()
。在你的对象上调用 __next__
将启动生成器并 return 它(此时没有魔法)。
在这种情况下,您 可能 完全不定义 __next__
就可以逃脱:
class MyString:
def __init__(self,s):
self.s=s
def __iter__(self):
for i in range(len(self.s)):
yield(self.s[i])
# Or...
# for item in self.s:
# yield item
如果你想使用 __iter__
和 __next__
(定义一个 iterator rather than simply making an iterable),你可能想做这样的事情:
class MyString:
def __init__(self,s):
self.s = s
self._ix = None
def __iter__(self):
return self
def __next__(self):
if self._ix is None:
self._ix = 0
try:
item = self.s[self._ix]
except IndexError:
# Possibly reset `self._ix`?
raise StopIteration
self._ix += 1
return item
让我们来看看__next__
方法的目的。来自 the docs:
iterator.__next__()
Return the next item from the container. If there are no further items, raise the StopIteration exception.
现在让我们看看 yield
语句的作用。 the docs 的另一段摘录:
Using a yield expression in a function’s body causes that function to be a generator
和
When a generator function is called, it returns an iterator known as a generator.
现在比较 __next__
和 yield
:__next__
return 容器中的下一个项目 。但是包含 yield
关键字的函数 return 是一个迭代器 。因此,在 __next__
方法中使用 yield
会产生一个产生迭代器的迭代器。
如果您想使用 yield
使您的 class 可迭代,请在 __iter__
方法中执行:
class MyString:
def __init__(self, s):
self.s = s
def __iter__(self):
for s in self.s:
yield s
__iter__
方法应该 return 一个迭代器 - 而 yield
关键字使它做到这一点。
为了完整起见,下面是如何使用 __next__
方法实现迭代器。您必须跟踪迭代的状态,以及 return 相应的值。最简单的解决方案可能是每次调用 __next__
时增加一个索引:
class MyString:
def __init__(self,s):
self.s = s
self.index = -1
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index >= len(self.s):
raise StopIteration
return self.s[self.index]
据我所知,生成器函数只是 classes 和 next 函数的语法糖。示例:
>>> def f():
i = 0
while True:
i += 1
yield i
>>> x = f()
>>> x
<generator object f at 0x0000000000659938>
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> class g(object):
def __init__(self):
self.i = 0
def __next__(self):
self.i += 1
return self.i
>>> y = g()
>>> y
<__main__.g object at 0x000000000345D908>
>>> next(y)
1
>>> next(y)
2
>>> next(y)
3
事实上,我来这里是想看看是否有任何显着差异。有的话请喊一声。
所以,要回答这个问题,您拥有的是一个 class 和 __next__ 方法,returns 一个对象也有一个 __next__ 方法。因此,最简单的做法是用 return
替换 yield
并跟踪你走了多远,并记住在到达数组末尾时引发 StopIteration 。所以像:
class MyString:
def __init__(self,s):
self.s=s
self._i = -1
def __iter__(self):
return self
def __next__(self):
self._i += 1
if self._i >= len(self.s):
raise StopIteration
return self.s[self._i]
这可能是实现我认为您正在寻找的东西的最简单方法。