是的,这与内置函数通常是用C语言实现有关。通常情况下,C代码会引入新类型而不是普通函数,例如enumerate
。
用C编写它们可以更好地控制它们,并且通常还可以提高性能,
而且没有任何实际的缺点,这是一个自然的选择。
请注意,要编写等价于以下内容的代码:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
在C中,即创建“生成器”的新实例,您应当创建一个包含实际字节码的代码对象。这并非不可能,但比编写简单实现Python C-API调用
__iter__
和
__next__
的新类型更加困难,而且具有不同类型的其他优势。
因此,在
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
,必须调用 PyFrame_New
函数,其签名如下:
PyFrameObject *
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyObject *locals)
正如您所看到的,它需要一个PyCodeObject
实例。PyCodeObject
是Python解释器在内部表示字节码的方式(例如,PyCodeObject
可以表示函数的字节码),因此:是的,要从C创建PyGen_Type
实例,您必须手动创建字节码。而且创建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语言中创建它,但我并不确定它所需的字符数是否比编写一个简单的新类型少。