查找用 C 实现的方法的源代码?

Finding the source code of methods implemented in C?

请注意,我问这个问题仅供参考

我知道标题听起来像 Finding the source code for built-in Python functions? 的副本。但是让我解释一下。

比如说,我想找到collections.Counterclass的most_common方法的源代码。由于 Counter class 在 python 中实现,我可以使用 inspect 模块获取它的源代码。

>>> import inspect
>>> import collections
>>> print(inspect.getsource(collections.Counter.most_common))

这将打印

    def most_common(self, n=None):
        '''List the n most common elements and their counts from the most
        common to the least.  If n is None, then list all element counts.

        >>> Counter('abcdeabcdabcaba').most_common(3)
        [('a', 5), ('b', 4), ('c', 3)]

        '''
        # Emulate Bag.sortedByCount from Smalltalk
        if n is None:
            return sorted(self.items(), key=_itemgetter(1), reverse=True)
        return _heapq.nlargest(n, self.items(), key=_itemgetter(1))

因此,如果方法或 class 在 C inspect.getsource 中实现,将引发 TypeError

>>> my_list = []
>>> print(inspect.getsource(my_list.append))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\abdul.niyas\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 968, in getsource
    lines, lnum = getsourcelines(object)
  File "C:\Users\abdul.niyas\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 955, in getsourcelines
    lines, lnum = findsource(object)
  File "C:\Users\abdul.niyas\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 768, in findsource
    file = getsourcefile(object)
  File "C:\Users\abdul.niyas\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 684, in getsourcefile
    filename = getfile(object)
  File "C:\Users\abdul.niyas\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 666, in getfile
    'function, traceback, frame, or code object'.format(object))
TypeError: <built-in method append of list object at 0x00D3A378> is not a module, class, method, function, traceback, frame, or code object.

所以我的问题是,有什么方法(或使用第三方包?)我们可以找到 class 的源代码或用 C 实现的方法吗?

也就是说,像这样

>> print(some_how_or_some_custom_package([].append))


int
PyList_Append(PyObject *op, PyObject *newitem)
{
    if (PyList_Check(op) && (newitem != NULL))
        return app1((PyListObject *)op, newitem);
    PyErr_BadInternalCall();
    return -1;
}

不,没有。 Python 没有可让您找到原始源文件的元数据。此类元数据必须由 Python 开发人员显式创建,但没有明确说明这样做会带来什么好处。

首先,绝大多数 Python 安装不包含 C 源代码。接下来,虽然您可以想象 Python 语言的用户能够阅读 Python 源代码,但 Python 的用户群非常广泛,并且很多人不知道 C 或者是对 C 代码的工作原理感兴趣,最后,即使是了解 C 的开发人员也不必阅读 Python C API documentation,如果您想了解 Python 代码库,这很快就会成为一项要求.

C 文件不直接映射到特定的输出文件,这与 Python 字节码缓存文件和脚本不同。除非您使用符号 table 创建调试版本,否则编译器不会在它输出的生成的目标文件 (.o) 中保留源文件名,链接器也不会记录什么 .o文件进入它产生的结果。也不是所有的 C 文件最终都贡献给同一个 executable 或动态共享目标文件;一些成为 Python 二进制文件的一部分,另一些成为可加载的扩展,并且混合是可配置的并且取决于编译时可用的外部库。

在 makefile、setup.py 和 C 预处理器宏之间,输入文件的组合以及实际用于创建每个输出文件的源代码行也各不相同。最后但并非最不重要的一点是,由于在运行时不再查阅 C 源文件,因此不能指望它们在相同的原始位置仍然可用,因此即使存储了一些元数据,您仍然无法将其映射回原来的。

所以,更容易记住一些关于Python C-API如何工作的基本规则,然后将其映射回C 代码和一些明智的代码搜索。

或者,下载 Python 源代码并创建一个调试版本,并使用一个好的 IDE 来帮助您将符号等映射回源文件。不同的编译器、平台和 IDEs 有不同的支持符号 tables 调试的方法。

如果您拥有完整的调试信息(通常会被删除),可能会有一种方法。

然后您将到达 sopyd,并使用特定于平台的工具提取调试信息(存储在 sopdb on Windows) 以获得所需的功能。您可能想查看 Linux 的 DWARF 信息(在 Windows 上,没有文档 AFAIK)。