11

在 Python 中似乎有两种方法可以测试一个对象是否是生成器:

import types
isinstance(foo, types.GeneratorType)

或者:

import inspect
inspect.isgenerator(foo)

本着“应该有一种——最好只有一种——明显的方式来做到这一点。”的精神,是推荐的这些方式之一(大概他们做同样的事情......如果没有,请赐教!)?

4

3 回答 3

9

它们是 100% 等效的:

>>> print(inspect.getsource(inspect.isgenerator))
def isgenerator(object):
    """Return true if the object is a generator.

    Generator objects provide these attributes:
        __iter__        defined to support interation over container
        close           raises a new GeneratorExit exception inside the
                        generator to terminate the iteration
        gi_code         code object
        gi_frame        frame object or possibly None once the generator has
                        been exhausted
        gi_running      set to 1 when generator is executing, 0 otherwise
        next            return the next item from the container
        send            resumes the generator and "sends" a value that becomes
                        the result of the current yield-expression
        throw           used to raise an exception inside the generator"""
    return isinstance(object, types.GeneratorType)

我会说 usingisinstance(object, types.GeneratorType)应该是首选方式,因为它更清晰,更简单。也inspect.isgenerator只在python2.6中添加,这意味着使用isinstance更加向后兼容。

他们可能添加了isgenerator对称功能,isgeneratorfunction它做了一些不同的事情。

于 2013-10-21T16:47:49.147 回答
2

您可以进行类型检查,但您可能不想只检查生成器。你真正想要的是检查'迭代器',或者更确切地说,你想要两个迭代器。

import collections, itertools

def cheap_tee(foo):
    if isinstance(foo, collections.Iterator):
        # this is already an iterator, we need to 'tee' it
        return itertools.tee(foo)
    elif isinstance(foo, collections.Iterable):
        # this is already an iterable, get two iterators from it:
        return iter(foo), iter(foo)
    raise TypeError("Don't know how to cheaply copy these", foo)

然后,这将适用于任何可远程迭代的东西,而不仅仅是生成器表达式。某些类型将提供自定义迭代器,这些迭代器适用于不容易用生成器表达式或生成器表示的数据结构,或者在 C 中作为迭代器实现。或者也可以提供一种可以实际使用并且不会打扰重复工作的__copy__机制,itertools.tee任何一个。只有当它真的已经是一个tee不能为你复制的迭代器时,它才会使用空间,为你完成所有的结晶。

于 2013-10-21T16:41:22.743 回答
1

你应该能够做到:

try:
    x = possible_generator.next()
    mylist = [x] + list(possible_generator)

except:
    pass

这将区分生成器和内置迭代器;但是,如果您有一个类似于列表但也实现了 next 的自定义类,那么它将失败。

于 2013-10-21T17:02:53.857 回答