2 回答
TA贡献2021条经验 获得超8个赞
当答案非常简单时,您正在寻找的是非常复杂的东西。
我什至不知道“通向所有渠道”是print什么意思,但是什么也不做。它所做的只是调用传递给它write的file对象。
然而,它要求write每进行一次的说法,每进行一次sep,并一度为end。
因此,此行:
print("Don't you ever disrespect the caterpillar", file=debug)
…大致相当于:
debug.write(str("Don't you ever disrespect the caterpillar"))
debug.write("\n")
……这当然意味着您print两次收到额外的消息。
顺便说一句,将来用于调试或理解这样的事情:如果您将多余的内容更改print为包括repr(obj),那么将是显而易见的:
def _debugwrite(obj):
print("stderring " + repr(obj))
out = sys.stderr
out.write(obj)
输出为:
stderring "Don't you ever disrespect the caterpillar"
stderring '\n'
Don't you ever disrespect the caterpillar
不再是很神秘了吧?
当然,stdout和stderr是独立的流,具有自己的缓冲区。(默认情况下,与TTY通话时,它stdout是行缓冲的,并且stderr是非缓冲的。)因此,排序不是您天真想要的,但这是有道理的。如果仅添加flushes,则输出将变为:
stderring "Don't you ever disrespect the caterpillar"
Don't you ever disrespect the caterpillarstderring '\n'
(末尾有空白行)。
对于您的奖金问题:
我试图使用检查模块来获取调用者,也许看到谁在写实际的调用,但是我得到了模块,idk为什么:(这很明显吗?
我假设你做了类似的事情inspect.stack()[1].function?如果是这样,则您要检查的代码是模块中的顶级代码,因此将其inspect显示为名为的伪函数<module>。
有什么方法可以调试Python以外的函数并进入基础C调用?
当然。只需在lldb,gdb,Microsoft的调试器或通常用于调试二进制程序的任何其他程序下运行CPython本身即可。您可以将断点放置在ceval循环中或特定的C API函数中,也可以放置在任意位置。您可能需要构建CPython的调试版本(请./configure --help参阅选项),以使其变得更好。
因为主要的Python发行版是CPython,如果我的理解是正确的,Python只是底层C代码的api。
好吧,不完全是。它是一个编译器和一个字节码解释器。该字节码解释器很大程度上使用与扩展/嵌入接口公开的相同的C API,但是重叠并不是100%;在某些地方它处理C API级别以下的结构。
Python中的调用最终在后台转换为C调用。因此,例如,我发现打印在C中的定义如下,但是对我来说很难理解那里发生了什么(因为erm,我不了解C),但是也许可以通过调试器来打印东西弄清楚是什么,如果不是全部的话,至少要弄清楚流程。我非常想了解引擎盖下的总体情况,而不是理所当然地认为。
是的,您可以这样做,但是您将需要同时理解C和CPython API(例如,如何查找与等价的C插槽之类的东西__call__),以找出放置断点并开始跟踪的位置。
对于这种情况,只用Python编写包装器并在Python中调试它们就容易得多。例如:
import builtins
def print(*args, **kwargs):
return builtins.print(*args, **kwargs)
或者,如果您担心print在其他模块中被调用,而不仅仅是在您的模块中被调用,您甚至可以将其隐藏在builtins:
builtins._print = builtins.print
def print(*args, **kwargs):
return builtins._print(*args, **kwargs)
builtins.print = print
现在,您可以在Python级别使用pdb中断每个调用print,而不必担心C。
当然,您甚至可以在PyPy或Jython或其他任何工具中调试此代码,以查看它与“内置”级别以上的CPython是否有任何不同。
添加回答
举报