Ors*_*ong 8 python built-in python-3.x
我正在寻找一种方法将异常的可打印输出更改为愚蠢的消息,以便了解有关 python 内部结构的更多信息(并与朋友搞混;),但到目前为止还没有成功。
考虑以下代码
try:
x # is not defined
except NameError as exc:
print(exc)
Run Code Online (Sandbox Code Playgroud)
代码应输出 name 'x' is not defined
我希望将输出更改为the name 'x' you suggested is not yet defined, my lord. Improve your coding skills.
到目前为止,我明白你不能改变,__builtins__因为它们被“烘焙”为 C 代码,除非:
我已经尝试了两种解决方案,但没有成功:
禁果解决方案:
from forbiddenfruit import curse
curse(BaseException, 'repr', lambda self: print("Test message for repr"))
curse(BaseException, 'str', lambda self: print("Test message for str"))
try:
x
except NameError as exc:
print(exc.str()) # Works, shows test message
print(exc.repr()) # Works, shows test message
print(repr(exc)) # Does not work, shows real message
print(str(exc)) # Does not work, shows real message
print(exc) # Does not work, shows real message
Run Code Online (Sandbox Code Playgroud)
字典覆盖解决方案:
import gc
underlying_dict = gc.get_referents(BaseException.__dict__)[0]
underlying_dict["__repr__"] = lambda self: print("test message for repr")
underlying_dict["__str__"] = lambda self: print("test message for str")
underlying_dict["args"] = 'I am an argument list'
try:
x
except NameError as exc:
print(exc.__str__()) # Works, shows test message
print(exc.__repr__()) # Works, shows test message
print(repr(exc)) # Does not work, shows real message
print(str(exc)) # Does not work, shows real message
print(exc) # Does not work, shows real message
Run Code Online (Sandbox Code Playgroud)
AFAIK, usingprint(exc)应该依赖于__repr__or __str__,但似乎该print函数使用了其他东西,即使在阅读BaseExceptionvia 的所有属性时我也找不到print(dir(BaseException))。谁能告诉我print在这种情况下有什么用途?
[编辑]
要添加更多上下文:
我试图解决的问题一开始是为了和一个程序员朋友开玩笑,但现在成为我了解更多 python 内部结构的挑战。
我没有试图解决真正的业务问题,我只是想更深入地了解 Python 中的事物。
我很困惑,print(exc)不会使用BaseException.__repr__或__str__实际上。
[/编辑]
我将解释您所描述的行为:
exc.__repr__()这只会调用您的 lambda 函数并返回预期的字符串。顺便说一句,您应该返回字符串,而不是在 lambda 函数中打印它。
print(repr(exc))现在,这是一条不同的路线CPython,您可以在 GDB 会话中看到这一点,它是这样的:
Python/bltinmodule.c:builtin_repr将调用Objects/object.c:PyObject_Repr-在本例中,该函数将 用作获取和调用实现PyObject *v内置函数的函数的唯一参数。该函数将根据结构字段中的值格式化错误消息:repr()BaseException_reprargs
(gdb) p ((PyBaseExceptionObject *) self)->args
$188 = ("name 'x' is not defined",)
Run Code Online (Sandbox Code Playgroud)
该args值是Python/ceval.c:format_exc_check_arg根据NAME_ERROR_MSG同一文件中设置的宏设置的。
更新: UTC 2020 年 11 月 8 日(星期日)20:19:26
测试.py:
import sys
import dis
def main():
try:
x
except NameError as exc:
tb = sys.exc_info()[2]
frame, i = tb.tb_frame, tb.tb_lasti
code = frame.f_code
arg = code.co_code[i + 1]
name = code.co_names[arg]
print(name)
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
测试:
# python test.py
x
Run Code Online (Sandbox Code Playgroud)
笔记:
我还建议观看PyCon 2016 的这段视频。