__builtin__模块中的许多迭代器"函数" 实际上都是作为类型实现的,即使文档将它们称为"函数".举个例子enumerate.文档说它相当于:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
Run Code Online (Sandbox Code Playgroud)
当然,这与我实施的完全一样.但是,我使用之前的定义运行了以下测试,并得到了:
>>> x = enumerate(range(10))
>>> x
<generator object enumerate at 0x01ED9F08>
Run Code Online (Sandbox Code Playgroud)
这是我的期望.但是,在使用该__builtin__版本时,我得到了这个:
>>> x = enumerate(range(10))
>>> x
<enumerate object at 0x01EE9EE0>
Run Code Online (Sandbox Code Playgroud)
由此我推断它被定义为
class enumerate:
def __init__(self, sequence, start=0):
# ....
def __iter__(self):
# ...
Run Code Online (Sandbox Code Playgroud)
而不是文档显示的标准形式.现在我可以理解它是如何工作的,以及它是如何与标准形式相同的,我想知道的是这样做的原因是什么.这种方式更有效吗?它是否与在C中实现的这些函数有关(我不知道它们是否存在,但我怀疑如此)?
我正在使用Python 2.7.2,以防万一差异很重要.
提前致谢.
是的,它与内置函数通常用C实现的事实有关.通常C代码将引入新类型而不是普通函数,如同的情况一样enumerate.用C语言编写它们可以更好地控制它们,并且通常会有一些性能改进,而且由于没有真正的缺点,它是一个自然的选择.
考虑到要写相当于:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
Run Code Online (Sandbox Code Playgroud)
在C中,即生成器的新实例,您应该创建一个包含实际字节码的代码对象.这并非不可能,但并不比编写一个简单实现__iter__和__next__调用Python C-API 的新类型以及具有不同类型的其他优点更容易.
所以,在这种情况下enumerate,reversed它只是因为它提供了更好的性能,而且它更易于维护.
其他优点包括:
chain.from_iterable).即使使用函数也可以这样做,但是您必须首先定义它们,然后手动设置属性,这看起来不那么干净.isinstance在iterables上.这可以允许一些优化(例如,如果您知道isinstance(iterable, itertools.repeat),那么您可以优化代码,因为您知道将产生哪些值.编辑:只是为了澄清我的意思:
在C中,即生成器的新实例,您应该创建一个包含实际字节码的代码对象.
查看Objects/genobject.c创建PyGen_Type实例的唯一函数是PyGen_New其签名是:
PyObject *
PyGen_New(PyFrameObject *f)
Run Code Online (Sandbox Code Playgroud)
现在,看着Objects/frameobject.c我们可以看到创建一个PyFrameObject你必须调用PyFrame_New,它有这个签名:
PyFrameObject *
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyObject *locals)
Run Code Online (Sandbox Code Playgroud)
如您所见,它需要一个PyCodeObject实例.PyCodeObjects是python解释器如何在内部表示字节码(例如,a PyCodeObject可以表示函数的字节码),所以:是的,PyGen_Type要从C 创建实例,你必须手动创建字节码,并且创建PyCodeObjects 并不是那么容易因为PyCode_New这个签名:
PyCodeObject *
PyCode_New(int argcount, int kwonlyargcount,
int nlocals, int stacksize, int flags,
PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
PyObject *filename, PyObject *name, int firstlineno,
PyObject *lnotab)
Run Code Online (Sandbox Code Playgroud)
注意它是如何包含的参数firstlineno,filename显然是由python源而不是其他C代码获得的.显然你可以在C中创建它,但我不能确定它比写一个简单的新类型需要更少的字符.