请注意,我问这个问题仅供参考。
我知道标题听起来像是查找内置 Python 函数的源代码? 的重复。但让我解释一下。
比如说,我想找到
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\username\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 968, in getsource
lines, lnum = getsourcelines(object)
File "C:\Users\username\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 955, in getsourcelines
lines, lnum = findsource(object)
File "C:\Users\username\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 768, in findsource
file = getsourcefile(object)
File "C:\Users\username\AppData\Local\Programs\Python\Python36-32\lib\inspect.py", line 684, in getsourcefile
filename = getfile(object)
File "C:\Users\username\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;
}
不,没有。 Python 无法提供可让您找到原始源文件的元数据。此类元数据必须由 Python 开发人员显式创建,而不会带来明显的好处。
首先,绝大多数 Python 安装不包含 C 源代码。其次,虽然您可以想象,Python 语言的用户能够阅读 Python 源代码,但 Python 的用户群非常广泛,其中很大一部分人不了解 C 或对 C 代码的工作原理感兴趣,最后,即使是开发人员知道 C 不能指望必须阅读 Python C API 文档,如果您想了解 Python 代码库,这很快就会成为一项要求。
与 Python 字节码缓存文件和脚本不同,C 文件不直接映射到特定的输出文件。除非您使用符号表创建调试版本,否则编译器不会在其输出的生成的目标文件 (.o
) 中保留源文件名,链接器也不会记录哪些
.o
文件进入其生成的结果。并非所有 C 文件最终都会生成相同的可执行文件或动态共享对象文件;有些成为 Python 二进制文件的一部分,另一些成为可加载扩展,并且组合是可配置的,并且取决于编译时可用的外部库。在 makefile、
setup.py
和 C 预压缩器宏之间,输入文件的组合以及实际用于创建每个输出文件的源代码行也有所不同。最后但并非最不重要的一点是,由于在运行时不再查阅 C 源文件,因此不能期望它们在相同的原始位置仍然可用,因此即使存储了一些元数据,您仍然无法将其映射回原来的。因此,只需记住一些有关 Python C-API 如何工作的基本规则,然后通过一些明智的代码搜索将其映射回 C 代码,就更容易了。
或者,下载 Python 源代码并创建调试版本,并使用良好的 IDE 来帮助您将符号等映射回源文件。不同的编译器、平台和 IDE 有不同的支持符号表进行调试的方法。
如果您拥有完整的调试信息(通常会被删除),那么可能有办法。
so
pyd
,并使用特定于平台的工具来提取所需功能的调试信息(存储在
so
或 Windows 上的
pdb
中)。您可能想查看 Linux 上的 DWARF 信息(据我所知,在 Windows 上没有文档)。