【问题标题】:Finding the source code of methods implemented in C?找到用 C 实现的方法的源代码?
【发布时间】:2019-03-28 20:20:11
【问题描述】:

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

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

比如说我想找到collections.Counter类的most_common方法的源代码。由于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;
}

【问题讨论】:

  • 我认为答案可能是否定的,除非您对 GitHub 进行某种抓取或反编译,因为您的本地计算机上可能根本不存在该源代码。 C 代码是在构建 python 发行版时编译的,您可能没有可用的 C 源文件。很想知道我错了,所以会留意这个问题。

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


【解决方案1】:

不,没有。没有可从 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 有不同的方法来支持符号表进行调试。

【讨论】:

    【解决方案2】:

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

    然后您将访问sopyd,并使用特定于平台的工具来提取所需功能的调试信息(存储在so 或Windows 上的pdb 中)。您可能想查看 Linux 的 DWARF 信息(在 Windows 上,没有文档 AFAIK)。

    【讨论】:

    • 即使在调试版本中,也没有足够的信息保留直接映射到源文件。
    • 而且分析器仍然可以做到(callgrind、tune...),而 gdb 可以。不是说这很容易,但它是可行的。如果您可能有源文件,效果会更好。
    猜你喜欢
    • 2016-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-10
    • 1970-01-01
    相关资源
    最近更新 更多