作为一个完整的Python新手,它肯定是这样的.运行以下...
x = enumerate(['fee', 'fie', 'foe'])
x.next()
# Out[1]: (0, 'fee')
list(x)
# Out[2]: [(1, 'fie'), (2, 'foe')]
list(x)
# Out[3]: []
Run Code Online (Sandbox Code Playgroud)
......我注意到:(a)x确实有一个next方法,似乎是生成器所需要的,而(b)x只能迭代一次,这个着名的python标签答案中强调了生成器的一个特征.
在另一方面,这两个最高度upvoted回答这个问题,
如何确定一个对象是否是发电机似乎表明,enumerate()它不会返回发电机.
import types
import inspect
x = enumerate(['fee', 'fie', 'foe'])
isinstance(x, types.GeneratorType)
# Out[4]: False
inspect.isgenerator(x)
# Out[5]: False
Run Code Online (Sandbox Code Playgroud)
......虽然对该问题的第三个低调的回答似乎表明实际上enumerate() 确实返回了一个发电机:
def isgenerator(iterable):
return hasattr(iterable,'__iter__') and not hasattr(iterable,'__len__')
isgenerator(x)
# Out[8]: True
Run Code Online (Sandbox Code Playgroud)
发生什么了?是x发电机还是没有?它在某种意义上是"类似发电机",但不是真正的发电机吗?Python使用duck-typing是否意味着上面最后一个代码块中概述的测试实际上是最好的?
我不会继续写下我头脑中可能存在的可能性,而是将其抛给那些立即知道答案的人.
dan*_*ano 33
虽然Python文档说它enumerate在功能上等同于:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
Run Code Online (Sandbox Code Playgroud)
实enumerate函数返回迭代器,但不是实际的生成器.如果help(x)在创建enumerate对象后调用,则可以看到此信息:
>>> x = enumerate([1,2])
>>> help(x)
class enumerate(object)
| enumerate(iterable[, start]) -> iterator for index, value of iterable
|
| Return an enumerate object. iterable must be another object that supports
| iteration. The enumerate object yields pairs containing a count (from
| start, which defaults to zero) and a value yielded by the iterable argument.
| enumerate is useful for obtaining an indexed list:
| (0, seq[0]), (1, seq[1]), (2, seq[2]), ...
|
| Methods defined here:
|
| __getattribute__(...)
| x.__getattribute__('name') <==> x.name
|
| __iter__(...)
| x.__iter__() <==> iter(x)
|
| next(...)
| x.next() -> the next value, or raise StopIteration
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| __new__ = <built-in method __new__ of type object>
| T.__new__(S, ...) -> a new object with type S, a subtype of T
Run Code Online (Sandbox Code Playgroud)
在Python中,生成器基本上是一种特定类型的迭代器,它通过使用a yield来从函数返回数据来实现.但是,enumerate实际上是用C实现的,而不是纯Python,所以没有yield涉及.你可以在这里找到源代码:http://hg.python.org/cpython/file/2.7/Objects/enumobject.c
Aar*_*all 10
我将在枚举类型的探索中以及它如何适合Python语言中包含这个重要的测试:
>>> import collections
>>> e = enumerate('abc')
>>> isinstance(e, enumerate)
True
>>> isinstance(e, collections.Iterable)
True
>>> isinstance(e, collections.Iterator)
True
Run Code Online (Sandbox Code Playgroud)
但我们看到:
>>> import types
>>> isinstance(e, types.GeneratorType)
False
Run Code Online (Sandbox Code Playgroud)
所以我们知道枚举对象不是生成器.
在源代码(Python 2.7)中,我们可以看到迭代返回元组的枚举对象(PyEnum_Type),在ABC模块中我们可以看到任何带有a 和方法(实际上是属性)的项被定义为迭代器.(在Python 3中)next__iter____next__
所以Abstract Base Class库使用以下测试:
>>> hasattr(e, 'next') and hasattr(e, '__iter__')
True
Run Code Online (Sandbox Code Playgroud)
所以我们知道枚举类型是迭代器.但是我们看到Generator类型是由 文档中的 yield 或生成器表达式的函数创建的.因此生成器是迭代器,因为它们具有next和__iter__方法,但并非所有迭代器都必须是生成器,正如我们在此枚举对象中看到的那样.
enumerate呢?从文档和源代码中,我们知道enumerate返回一个枚举对象,我们知道它是一个迭代器,即使我们的测试声明它明确不是一个生成器.
我们还从文档中了解到,生成器类型只是" 提供了一种实现迭代器协议的便捷方式. "因此,生成器是迭代器的子集.此外,这允许我们推导出以下概括:
所有生成器都是迭代器,但并非所有迭代器都是生成器.
因此,虽然我们可以将枚举对象变为生成器:
>>> g = (i for i in e)
>>> isinstance(g, types.GeneratorType)
True
Run Code Online (Sandbox Code Playgroud)
我们不能指望它本身就是一个发电机,所以这将是错误的测试.
这意味着你不应该测试一个生成器,你应该使用我提供的第一个测试,而不是重新实现标准库(我希望今天可以免除这个).
如果需要枚举类型,您可能希望允许带有整数索引的元组的迭代或迭代器,并且以下内容将返回True:
isinstance(g, collections.Iterable)
Run Code Online (Sandbox Code Playgroud)
如果您只需要特定的枚举类型:
isinstance(e, enumerate)
Run Code Online (Sandbox Code Playgroud)
PS如果你感兴趣,这里是生成器的源代码实现:http://hg.python.org/cpython/file/785e29d8ce13/Objects/genobject.c
| 归档时间: |
|
| 查看次数: |
6233 次 |
| 最近记录: |