在运行下面的脚本时,我(对我)遇到了一点奇怪的行为。你知道吗
如您所见,似乎write
被多次调用,我想知道为什么会这样,因为我已经显式地重写了file=sys.stdout
行为。你知道吗
究竟如何打印管道流下引擎盖,它管道到所有渠道?它是否有一些默认行为,the docs除了以下几点之外,不是很具体:
The file argument must be an object with a write(string) method; if it is not present or None, sys.stdout will be used.
测试脚本
import sys
def debug(*args, **kwargs):
pass
def _debugwrite(obj):
print("You're looking at Attila, the psychopathic killer, the caterpillar")
out = sys.stderr
out.write(obj)
debug.write = _debugwrite
print("Don't you ever disrespect the caterpillar", file=debug)
输出:
You're looking at Attila, the psychopathic killer, the caterpillar
You're looking at Attila, the psychopathic killer, the caterpillar
Don't you ever disrespect the caterpillar
我所期望的:
You're looking at Attila, the psychopathic killer, the caterpillar
Don't you ever disrespect the caterpillar
我试过的:
我尝试使用inspect
模块来获取调用者,也许可以看到谁实际调用了write,但是我得到了module
,idk为什么:(这很明显吗?你知道吗
进一步的问题:
有没有办法调试Python
之外的函数并进入底层的C
调用?因为主要的Python
分布是CPython
,如果我的理解是正确的,Python
只是底层C
代码的api
。在Python
中的调用最终会被转换成C
在引擎盖下的调用。例如,我发现print
is defined as follows in C,但我很难理解那里发生了什么(因为,呃,我不知道C
),但也许通过使用调试器,我可以打印出一些东西,看看是什么,如果不是所有的话,至少可以找出流程。我很想了解引擎盖下发生了什么,而不是想当然。你知道吗
提前谢谢你的时间!你知道吗
得到您看到的结果是因为
builtin_print()
调用PyFile_Write*()
两次,一次是为了print the argument,另一次是为了print the EOL。它们是无序的,因为默认情况下stderr是无缓冲的,stdout是行缓冲的。你知道吗当答案非常简单的时候,你在寻找一些非常复杂的东西。你知道吗
我甚至不知道“管道到所有通道”是什么意思,但是
print
并没有这样做。它所做的就是调用传递给它的write
对象。你知道吗但是,它为每个参数调用一次
write
,为每个sep
调用一次,为end
调用一次。你知道吗所以,这一行:
…大致相当于:
…这当然意味着你会收到两次额外的
print
信息。你知道吗顺便说一句,为了将来调试或理解这样的事情:如果您将额外的
print
更改为包含,比如说repr(obj)
,发生的事情将是显而易见的:然后输出为:
不再那么神秘了,对吧?你知道吗
当然
stdout
和stderr
是独立的流,有各自的缓冲区。(默认情况下,当与TTY交谈时,stdout
是行缓冲的,stderr
是无缓冲的。)因此排序不是您天真地期望的,而是有意义的。如果只添加flush
es,则输出将变成:(结尾有一个空行)。你知道吗
对于您的奖励问题:
我假设你做了类似于
inspect.stack()[1].function
的事?如果是这样,那么您要检查的代码就是模块中的顶级代码,因此inspect
将其显示为名为<module>
的伪函数。你知道吗当然。只需在lldb、gdb、微软的调试器或其他通常用于调试二进制程序的工具下运行CPython本身。您可以将断点放在
ceval
循环或特定的C API函数中或任何您想要的地方。您可能希望对CPython进行调试构建(do./configure help
以查看选项),从而使其更加完善。你知道吗嗯,不是很好。它是一个编译器和一个字节码解释器。字节码解释器很大程度上使用了为扩展/嵌入接口公开的相同的C API,但是重叠不是100%;有些地方它处理的结构低于C API级别。你知道吗
是的,您可以这样做,但是您需要同时了解C和cpythonapi(例如,如何找到等价于
__call__
的C插槽),以确定在何处放置断点并开始跟踪。你知道吗对于这样的情况,用Python编写包装器并用Python调试它们要容易得多。例如:
或者,如果您担心
print
在其他模块中被调用,而不仅仅是在您的模块中,您甚至可以将它隐藏在builtins
:现在您可以在Python级别使用
pdb
中断对print
的每次调用,而不用担心C当然,您甚至可以在PyPy或Jython中调试这些代码,看看它是否与“内置”级别以上的CPython有所不同。你知道吗
相关问题 更多 >
编程相关推荐