为了账号安全,请及时绑定邮箱和手机立即绑定

Python如何打印全栈,包括使用的魔术方法(dunder methods)?

Python如何打印全栈,包括使用的魔术方法(dunder methods)?

暮色呼如 2022-10-06 20:20:47
我正在尝试调试 Python 内置类。我的调试使我进入了魔术方法(又名 dunder 方法)的领域。我试图找出调用了哪些 dunder 方法,如果有的话。通常我会做这样的事情:import sysimport traceback# This would be located where the I'm currently debuggingtraceback.print_stack(file=sys.stdout)但是,traceback.print_stack并没有给我打印在其附近使用的 dunder 方法区域的详细程度。有什么方法可以以非常详细的方式打印出代码块中实际发生的事情?示例代码#!/usr/bin/env python3.6import sysimport tracebackfrom enum import Enumclass TestEnum(Enum):    """Test enum."""    A = "A"def main():    for enum_member in TestEnum:        traceback.print_stack(file=sys.stdout)        print(f"enum member = {enum_member}.")if __name__ == "__main__":    main()我希望上面的示例代码打印出任何使用的 dunder 方法(例如:)__iter__。目前它打印出调用的路径traceback.print_stack:/path/to/venv/bin/python /path/to/file.py  File "/path/to/file.py", line 56, in <module>    main()  File "/path/to/file.py", line 51, in main    traceback.print_stack(file=sys.stdout)enum member = TestEnum.A.PS 我对进入 . 给出的字节码级别不感兴趣dis.dis。
查看完整描述

2 回答

?
杨魅力

TA贡献1811条经验 获得超6个赞

我认为,使用堆栈跟踪,您正在寻找错误的地方。当您print_stack从一个地方调用时,该方法仅在来自 dunder 方法时执行,该方法很好地包含在输出中。


我试过这段代码来验证:


import sys

import traceback

from enum import Enum



class TestEnum(Enum):

    """Test enum."""


    A = "A"



class MyIter:


    def __init__(self):

        self.i = 0


    def __next__(self):

        self.i += 1

        if self.i <= 1:

            traceback.print_stack(file=sys.stdout)

            return TestEnum.A

        raise StopIteration


    def __iter__(self):

        return self



def main():

    for enum_member in MyIter():

        print(f"enum member = {enum_member}.")



if __name__ == "__main__":

    main()

堆栈跟踪的最后一行打印为


File "/home/lydia/playground/demo.py", line 21, in __next__

traceback.print_stack(file=sys.stdout)

在您的原始代码中,您在所有 dunder 方法都已返回时获取堆栈跟踪。因此,它们已从堆栈中删除。


所以我认为,你想看看调用图。我知道 IntelliJ / PyCharm 至少在付费版本中可以很好地做到这一点。


您可能还想尝试其他工具。你觉得 pycallgraph怎么样?


更新:


Python 使得转储所有函数调用的简单列表实际上非常容易。


基本上你需要做的就是


import sys

sys.setprofile(tracefunc)

tracefunc根据您的需要编写。在这个 SO 问题上找到一个工作示例:How do I print functions as they are called

警告:我需要从外部 shell 启动脚本。通过在我的 IDE 中使用播放按钮启动它意味着脚本永远不会终止,而是编写越来越多的行。我认为它与我的 IDE 完成的内部分析相冲突。

官方文档sys.setprofilehttps ://docs.python.org/3/library/sys.html#sys.setprofile

还有一个关于 Python 跟踪的随机教程:https ://pymotw.com/2/sys/tracing.html

但是请注意,根据我的经验,您可以对“谁在给谁打电话?”这个问题获得最好的见解。或者“这个价值是从哪里来的?” 通过使用普通的调试器。


查看完整回答
反对 回复 2022-10-06
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

我还对该主题进行了一些研究,因为@LydiaVanDyke 的答案中的信息促进了更好的搜索。

打印整个调用堆栈

正如@LydiaVanDyke 指出的那样,IDE 调试器是一个非常好的方法。我使用 PyCharm,发现这是我最喜欢的解决方案,因为可以:

  • 遵循函数调用 + 代码中的确切行号

  • 阅读调用周围的代码,更好地理解打字

  • 跳过不想调查的电话

另一种方法是 Python 的标准库的trace. 它提供了命令行和可嵌入的方法来打印整个调用堆栈。

还有一个是 Python 的内置调试器模块,pdb. 这(通过调用pdb.set_trace())真的改变了我的游戏。

Profiler 输出的可视化

gprof2dot是另一个有用的分析器可视化工具。

查找源代码

由于我的 IDE 的存根文件 (PyCharm),我的其他问题之一实际上并没有看到真正的源代码。

如何检索Python函数的源代码详述了实际打印源代码的两种方法


使用所有这些工具,您会感到非常有能力!


查看完整回答
反对 回复 2022-10-06
  • 2 回答
  • 0 关注
  • 126 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信