isinstance(foo,types.GeneratorType)或inspect.isgenerator(foo)?

时间:2013-10-21 16:35:54

标签: python performance

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

import types
isinstance(foo, types.GeneratorType)

或:

import inspect
inspect.isgenerator(foo)

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

3 个答案:

答案 0 :(得分:7)

它们是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)

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

他们可能为对称性isgeneratorfunction添加了isgenerator函数,它做了不同的事情。

答案 1 :(得分: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实际使用也不会打扰重复工作。只有当它'真的已经是{{1}}无法为你复制的迭代器时,它才会使用空间,为你做所有的结晶。

答案 2 :(得分:1)

你应该能够做到:

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

except:
    pass

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