是的,这与内置函数通常在 C 中实现这一事实有关。实际上,C 代码通常会引入新类型而不是普通函数,例如enumerate
. 用 C 语言编写它们可以更好地控制它们,并且通常会提高一些性能,并且由于没有真正的缺点,这是一个自然的选择。
考虑到编写相当于:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
在 C 中,即生成器的新实例,您应该创建一个包含实际字节码的代码对象。这不是不可能的,但并不比编写一个简单地实现__iter__
和__next__
调用 Python C-API 的新类型容易,再加上拥有不同类型的其他优点。
所以,在 and 的情况下enumerate
,reversed
这仅仅是因为它提供了更好的性能,并且更易于维护。
其他优点包括:
- 您可以将方法添加到类型(例如
chain.from_iterable
)。即使使用函数也可以做到这一点,但是您必须先定义它们,然后手动设置属性,这看起来不太干净。
- 您可以
isinstance
在可迭代对象上使用我们。这可能允许一些优化(例如,如果您知道isinstance(iterable, itertools.repeat)
,那么您可能能够优化代码,因为您知道将产生哪些值。
编辑:只是为了澄清我的意思:
在 C 中,即生成器的新实例,您应该创建一个包含实际字节码的代码对象。
查看Objects/genobject.c
创建PyGen_Type
实例的唯一函数是PyGen_New
其签名是:
PyObject *
PyGen_New(PyFrameObject *f)
现在,Objects/frameobject.c
我们可以看到要创建一个PyFrameObject
you must call PyFrame_New
,它具有以下签名:
PyFrameObject *
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyObject *locals)
如您所见,它需要一个PyCodeObject
实例。PyCodeObject
s 是python解释器如何在内部表示字节码(例如 aPyCodeObject
可以表示函数的字节码),所以:是的,PyGen_Type
要从 C 创建一个实例,您必须手动创建字节码,而且创建 s 并不容易,PyCodeObject
因为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)
请注意它如何包含诸如 之类的参数firstlineno
,filename
这些参数显然是由 python 源而不是从其他 C 代码中获取的。显然,您可以在 C 中创建它,但我完全不确定它是否需要比编写简单的新类型更少的字符。