你如何调查Python内置方法的实现?

7

我目前正在学习一门基础的计算机科学课程,我们经常使用Python的in方法。我很好奇这个方法是如何实现的,它背后的代码是什么样子的。

我可以想象出我自己实现这个方法的方式,但是在提交了几份作业之后,我发现我的做法通常很糟糕和低效。因此,我想开始调查“好”的代码。


"in"是一个不幸的例子 - 它不是单个函数(除非您将底层字节码解释器计算为一个函数,但在那里事情变得混乱,并且只进行低级别的记账),它是右操作数的一种方法。更糟糕的是,有一个特殊情况确实有一个默认实现,埋藏在字节码解释器的深处。 - user395760
1
@delnan,实际上这并不太糟糕。当我在扩展我的答案时搜索它时,它只是延迟到abstract.c中的一个函数,因此您实际上不必查看字节码解释器以查看in的实现。 - Devin Jeanpierre
@DevinJeanpierre 谢谢,我对这些内部机制不是很熟悉 - 我只知道 in 有自己的字节码指令,应该猜到他们会重用 C-API 实现的代码。 - user395760
4个回答

10
关于内置函数、类型和运算符等的一件事情是,它们 不是 由Python实现。相反,它们是由C语言实现的,这是一种更加繁琐和冗长的编程语言,通常无法很好地转换为Python(通常因为Python有更简单的方式)。
话虽如此,您可以通过公共源代码存储库在线调查Python的所有实现。 in 的实现是分散的--每种类型都有一个实现,以及一个更一般的实现调用特定于类型的实现(稍后详细说明)。例如,对于列表,我们将寻找列表的实现。在Python源代码树中,所有内置对象的源代码都在Objects目录中。在那个目录中,您会找到listobject.c,其中包含了列表对象及其所有方法的实现。
在回答时的存储库中,如果您查看第393行,您将找到in运算符的实现(也称为__contains__方法,这解释了函数的名称)。它相当简单,只需循环遍历列表的所有元素,直到找到元素或没有更多元素,并返回搜索结果。 :)
如果有帮助的话,在Python中编写这个的惯用方式是:
def __contains__(self, obj):
    for item in self:
        if item == obj:
            return True

    return False

我之前提到有一个更通用的实现方式。可以在abstract.c中的PySequence_Contains的实现中看到。它尝试调用特定于类型的版本,如果失败,则转而进行常规迭代。那个循环是在使用Python C-API将常规Python for循环编写为C时的样子。

C很痛苦吗?只有你不懂它时才是。 - Bryan Oakley
3
@Bryan,C语言出了名地难以调试。如果你不同意这种声名,那也可以。我不是要发生争论。(公平地说,一旦你学会了Valgrind,C语言的调试会变得容易得多 :) - Devin Jeanpierre
我会C语言,也会Python,但是C更加痛苦。虽然有人建议过,但并没有“混淆Python竞赛”。 - morningstar

6

从Python语言参考手册的数据模型部分:

成员测试运算符(innot in)通常是通过对序列进行迭代来实现的。然而,容器对象可以提供以下特殊方法,以更有效的实现,也不需要对象是一个序列。

object.__contains__(self, item)

调用以实现成员测试运算符。如果item在self中,则应返回true,否则返回false。对于映射对象,这应该考虑映射的键而不是值或键-项对。

对于未定义__contains__()的对象,成员测试首先尝试通过__iter__()进行迭代,然后尝试旧的序列迭代协议通过__getitem__(),请参阅语言参考中的此部分。

因此,默认情况下,Python迭代序列以实现in运算符。如果一个对象定义了__contains__方法,Python会使用它来替代迭代。那么在__contains__方法中会发生什么?要确切地知道,您需要浏览源代码。但我可以告诉您,Python的列表使用迭代实现__contains__。Python字典和集合是作为哈希表实现的,因此支持更快的成员测试。


2
Python内置的方法是用C语言编写的 - 您可以通过检查Python源代码自己来查看它们的代码。
然而,如果您想查看Python本身所有方法的等效实现,您可以查看PyPy - 它具有完全由Python编写的Python实现和其子集(rpython)。 in运算符在字符串对象中调用__contains__方法 - 因此您可以检查两个项目中字符串的实现 - 但实际搜索代码将被深埋。
以下是CPython中的一些代码示例:

http://hg.python.org/cpython/file/c310233b1d64/Objects/stringlib/fastsearch.h


2
“PyPy is in Python”这个说法只是故事的一半。事实上:在实践中,RPython与Python有很大不同,而PyPy的Python解释器是一种非常灵活的实现相当复杂的语言。它分布在数百个文件中,使用了大量的间接引用,具有所有特殊情况的复杂逻辑,有很多仅用于优化的代码,并经常回到非常低级别的代码,包括普通的C语言。它尽可能简单,但我不认为大多数本科生能够掌握它。 - user395760

0

您可以在线浏览Python源代码:http://hg.python.org/

一个好的开始是克隆您需要的存储库,然后使用grep查找您需要的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接