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

时间:2018-10-24 12:08:25

标签: python-3.x cpython python-internals

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

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

例如,我想找到most_common类的collections.Counter方法的源代码。由于Counter类是用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))

因此,如果方法或类在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.

所以我的问题是,有什么办法(或使用第三方程序包?),我们还能找到用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;
}

2 个答案:

答案 0 :(得分:7)

不,没有。没有可从Python访问的元数据,可以让您查找原始源文件。这样的元数据必须由Python开发人员显式创建,而对其实现没有明显的好处。

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

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

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

因此,只需记住一些关于Python C-API如何工作的基本规则,然后通过一些明智的代码搜索将其映射回C代码,这很容易。

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

答案 1 :(得分:1)

如果您拥有完整的调试信息(通常会剥离这些信息),则可能是一种方法。

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