Python 只有作为generator func实现的_uiter__;要使用next()

Python 只有作为generator func实现的_uiter__;要使用next(),python,python-3.x,iterator,Python,Python 3.x,Iterator,我有一个\uuuu iter\uuuu类,定义如下: class MyIterator: def __iter__(self): for value in self._iterator: if is_iterator(value): yield from value else: yield value 我想做next(我的迭代器),但我必须实现\uuuuuu

我有一个
\uuuu iter\uuuu
类,定义如下:

class MyIterator:

    def __iter__(self):
        for value in self._iterator:
            if is_iterator(value):
                yield from value
            else:
                yield value
我想做
next(我的迭代器)
,但我必须实现
\uuuuuuuuuuuuuuuuuu
。但是它会把这个简单的实现变成一个相当复杂的实现——或者实际上我不知道如何实现它,而不是将
\uuu iter\uuu
定义为一个生成器函数

一般来说,如果将
\uuuuu iter\uuuuu
实现为一个生成器功能,如果没有生成器可能很难实现,那么如果我想使用
\uuuuu next\uuu


注:显然,
next(iter(我的迭代器))
有效,但我不想这样做。

正如@BrenBarm评论的那样,显然的答案是通过保持
self来返回
next(iter(self))
,或者
next(self.\iter\u self)
。正如@BrenBarm评论的那样,显然的答案是返回
next(iter(self))
,或者
next(self.\u iter\u self)
,保持
self.\u iter\u self=iter(self)
。我不能就这么想。

  • 迭代器是一个具有
    \uuuuuuuuuuuuuuuuuuuuuuuu
    方法的对象,该方法返回值,直到最后引发
    StopIteration
  • iterable是具有返回迭代器的
    \uuuuu iter\uuuu
    方法的对象
  • 生成器是python在函数或方法包含yield语句时创建的一个特殊的iterable
在您的示例中,
\uuuuuuuuuuuuuuu iter\uuuuuuuu
具有收益率,因此它是一个生成器。这意味着它返回另一个iterable,而不是迭代器。这就是为什么你必须下一步(iter(my_iterator))
去做一件奇怪的事情,但这不起作用,因为它每次都会重新启动枚举

如何最好地解决这个问题取决于您如何使用这个类。您可以创建一个生成器函数,然后根据需要使用
iter
生成迭代器:

import collections.abc

def is_iterator(i):
    return isinstance(i, collections.abc.Iterable)

def MyIterator(iterable):
    for value in iterable:
        if is_iterator(value):
            yield from value
        else:
            yield value

test_this = [1,2, [3, 4, 5], [6], [], 7, 'foo']
my_iterator = iter(MyIterator(test_this))
try:
    while True:
        print(next(my_iterator))
except StopIteration:
    pass
或者,您可以实现
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但是您不能使用
yield
,并且必须在每次调用时返回一个值,直到外部迭代器完成并引发
StopIteration

import collections.abc

class MyIterator:

    def __init__(self, iterable):
        self._iterator = iter(iterable)
        self._iterating = None

    def __next__(self):
        while True:
            if self._iterating is not None:
                try:
                    return next(self._iterating)
                except StopIteration:
                    self._iterating = None
            value = next(self._iterator)
            if isinstance(value, collections.abc.Iterable):
                self._iterating = iter(value)
            else:
                return value


test_this = [1,2, [3, 4, 5], [6], [], 7, 'foo']
my_iterator = MyIterator(test_this)
try:
    while True:
        print(next(my_iterator))
except StopIteration:
    pass
  • 迭代器是一个具有
    \uuuuuuuuuuuuuuuuuuuuuuuu
    方法的对象,该方法返回值,直到最后引发
    StopIteration
  • iterable是具有返回迭代器的
    \uuuuu iter\uuuu
    方法的对象
  • 生成器是python在函数或方法包含yield语句时创建的一个特殊的iterable
在您的示例中,
\uuuuuuuuuuuuuuu iter\uuuuuuuu
具有收益率,因此它是一个生成器。这意味着它返回另一个iterable,而不是迭代器。这就是为什么你必须下一步(iter(my_iterator))
去做一件奇怪的事情,但这不起作用,因为它每次都会重新启动枚举

如何最好地解决这个问题取决于您如何使用这个类。您可以创建一个生成器函数,然后根据需要使用
iter
生成迭代器:

import collections.abc

def is_iterator(i):
    return isinstance(i, collections.abc.Iterable)

def MyIterator(iterable):
    for value in iterable:
        if is_iterator(value):
            yield from value
        else:
            yield value

test_this = [1,2, [3, 4, 5], [6], [], 7, 'foo']
my_iterator = iter(MyIterator(test_this))
try:
    while True:
        print(next(my_iterator))
except StopIteration:
    pass
或者,您可以实现
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但是您不能使用
yield
,并且必须在每次调用时返回一个值,直到外部迭代器完成并引发
StopIteration

import collections.abc

class MyIterator:

    def __init__(self, iterable):
        self._iterator = iter(iterable)
        self._iterating = None

    def __next__(self):
        while True:
            if self._iterating is not None:
                try:
                    return next(self._iterating)
                except StopIteration:
                    self._iterating = None
            value = next(self._iterator)
            if isinstance(value, collections.abc.Iterable):
                self._iterating = iter(value)
            else:
                return value


test_this = [1,2, [3, 4, 5], [6], [], 7, 'foo']
my_iterator = MyIterator(test_this)
try:
    while True:
        print(next(my_iterator))
except StopIteration:
    pass

如果您的类应该是迭代器,那么它不应该将其
\uuuuu iter\uuuu
方法实现为生成器函数。这使得类是可重用的,但不是迭代器。迭代器的
\u iter\u
方法应该返回自身

如果您确实希望类成为迭代器,请尝试以下操作:

class MyIterator:
    def __init__(self, iterator):
        self._iterator = iterator
        self._subiterator = None

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            if self._subiterator is None:
                value = next(self._iterator) # may raise StopIteration

                try:  # could test is_iterator(value) here for LBYL style code
                    self._subiterator = iter(value)
                except TypeError:
                    return value

            try:
                return next(self._subiterator)
            except StopIteraton:
                self._subiterator = None
next(self.\u迭代器)
调用可能会引发
StopIteration
,我故意没有捕捉到它。这个异常是我们已经完成迭代的信号,所以如果我们捕捉到它,我们只需要再次引发它

这段代码使用了一种“请求原谅比请求许可更容易”(EAFP)的方法来检测给定迭代器中的iterable项。它只需在每一个上调用
iter
,并捕获
TypeError
,如果它们不可编辑,则会引发该错误。如果您更愿意坚持“三思而后行”(LBYL)风格,并使用
is_iterator
显式测试(名称不好,因为它检查的是任何类型的iterable,而不仅仅是iterator),您可以将内部
try
替换为:

if is_iterator(value):
    return value
else:
    self._subiterator = iter(value)

在Python代码中,我通常更喜欢EAFP样式而不是LBYL样式,但在某些情况下,两者都可以做得更好。其他时候,这只是风格的问题。

如果你的类应该是一个迭代器,那么它不应该把它的
\uuuu iter\uuu
方法实现为生成器函数。这使得类是可重用的,但不是迭代器。迭代器的
\u iter\u
方法应该返回自身

如果您确实希望类成为迭代器,请尝试以下操作:

class MyIterator:
    def __init__(self, iterator):
        self._iterator = iterator
        self._subiterator = None

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            if self._subiterator is None:
                value = next(self._iterator) # may raise StopIteration

                try:  # could test is_iterator(value) here for LBYL style code
                    self._subiterator = iter(value)
                except TypeError:
                    return value

            try:
                return next(self._subiterator)
            except StopIteraton:
                self._subiterator = None
next(self.\u迭代器)
调用可能会引发
StopIteration
,我故意没有捕捉到它。这个异常是我们已经完成迭代的信号,所以如果我们捕捉到它,我们只需要再次引发它

这段代码使用了一种“请求原谅比请求许可更容易”(EAFP)的方法来检测给定迭代器中的iterable项。它只需在每一个上调用
iter
,并捕获
TypeError
,如果它们不可编辑,则会引发该错误。如果您更愿意坚持“三思而后行”(LBYL)风格,并使用
is_iterator
显式测试(名称不好,因为它检查的是任何类型的iterable,而不仅仅是iterator),您可以将内部
try
替换为:

if is_iterator(value):
    return value
else:
    self._subiterator = iter(value)

在Python代码中,我通常更喜欢EAFP样式而不是LBYL样式,但在某些情况下,两者都可以做得更好。其他时候,这只是风格的问题。

您需要更多地解释您打算如何进行迭代。你可以在下一步写一个