Python更改Exception可打印的输出,例如__builtins__重载 [英] Python change Exception printable output, eg overload __builtins__
问题描述
我正在寻找一种将Exception的可打印输出更改为愚蠢消息的方法,以便进一步了解python内部信息(并与朋友;混乱),
考虑以下代码
try:x#未定义除了NameError作为exc:打印(EXC)
代码应输出未定义名称'x'
我希望将输出为您建议的名称'x'的更改尚未定义,我的主.提高您的编码技能
.
到目前为止,我了解到您无法更改 __ builtins __
,因为它们已经烘焙"到了作为C代码,除非:
- 您使用forbiddenfruit.curse方法来添加/更改任何对象的属性
- 您手动覆盖对象的字典
我尝试过两种解决方案,但都没有成功:
禁果解决方案:
从禁果进口诅咒curse(BaseException,'repr',lambda self:print("repr的测试消息"))curse(BaseException,'str',lambda self:print("str的测试消息"))尝试:X除了NameError作为exc:print(exc.str())#工作,显示测试消息print(exc.repr())#工作,显示测试消息print(repr(exc))#不起作用,显示真实消息print(str(exc))#不起作用,显示真实消息print(exc)#不起作用,显示真实消息
字典覆盖解决方案:
import gc底层_dict = gc.get_referents(BaseException .__ dict __)[0]underlying_dict ["__ repr__"] = lambda self:print("repr的测试消息")underlying_dict ["__ str__"] = lambda self:print("str的测试消息")underlying_dict ["args"] =我是参数列表"尝试:X除了NameError作为exc:print(exc .__ str __())#工作,显示测试消息print(exc .__ repr __())#工作,显示测试消息print(repr(exc))#不起作用,显示真实消息print(str(exc))#不起作用,显示真实消息print(exc)#不起作用,显示真实消息
使用 print(exc)
的
AFAIK应该依赖 __ repr __
或 __ str __
,但看起来像 print
函数使用其他东西,即使通过 print(dir(BaseException))
读取 BaseException
的所有属性,我也找不到.有人可以给我介绍在这种情况下使用什么 print
吗?
要添加更多上下文:
我要解决的问题始于开玩笑,与一个程序员朋友打成一片,但现在对我来说,要了解更多有关python内部结构的挑战成为了一个挑战.
我没有要解决的实际业务问题,我只是想更深入地了解Python中的内容.我很困惑,实际上 print(exc)
不会使用 BaseException .__ repr __
或 __ str __
.
[/EDIT]
我将解释您描述的行为:
-
exc .__ repr __()
这只会调用您的lambda函数并返回预期的字符串.顺便说一句,您应该返回该字符串,而不是在lambada函数中将其打印出来.
-
print(repr(exc))
现在,这在 CPython
中走了一条不同的路线,您可以在GDB会话中看到这一点,就像这样:
Python/bltinmodule.c:builtin_repr
将调用 Objects/object.c:PyObject_Repr
-此函数获取 PyObject * v
作为在这种情况下,它将是用于获取和调用实现内置函数 repr()
, BaseException_repr
的函数的唯一参数.此函数将根据 args
结构字段中的值来格式化错误消息:
(gdb)p((PyBaseExceptionObject *)self)-> args$ 188 =(未定义名称'x'",)
args
值是根据同一文件中设置的 NAME_ERROR_MSG
宏在 Python/ceval.c:format_exc_check_arg
中设置的.>
更新时间:UTC 2020年11月8日星期日20:19:26
test.py:
import sys导入disdef main():尝试:X除了NameError作为exc:tb = sys.exc_info()[2]框架,i = tb.tb_frame,tb.tb_lasti代码= frame.f_codearg = code.co_code [i + 1]名称= code.co_names [arg]打印(名称)如果__name__ =='__main__':主要的()
测试:
#python test.pyX
注意:
我还建议您观看PyCon 2016上的这视频.
I am searching for a way to change the printable output of an Exception to a silly message in order to learn more about python internals (and mess with a friend ;), so far without success.
Consider the following code
try:
x # is not defined
except NameError as exc:
print(exc)
The code shall output name 'x' is not defined
I would like the change that output to the name 'x' you suggested is not yet defined, my lord. Improve your coding skills
.
So far, I understood that you can't change __builtins__
because they're "baked in" as C code, unless:
- You use forbiddenfruit.curse method which adds / changes properties of any object
- You manually override the dictionnaries of an object
I've tried both solutions, but without success:
forbiddenfruit solution:
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
Dictionnary overriding solution:
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
AFAIK, using print(exc)
should rely on either __repr__
or __str__
, but it seems like the print
function uses something else, which I cannot find even when reading all properties of BaseException
via print(dir(BaseException))
.
Could anyone give me an insight of what print
uses in this case please ?
[EDIT]
To add a bit more context:
The problem I'm trying to solve began as a joke to mess with a programmer friend, but now became a challenge for me to understand more of python's internals.
There's no real business problem I'm trying to solve, I just want to get deeper understanding of things in Python.
I'm quite puzzled that print(exc)
won't make use of BaseException.__repr__
or __str__
actually.
[/EDIT]
I'll just explain the behaviour you described:
exc.__repr__()
This will just call your lambda function and return the expected string. Btw you should return the string, not print it in your lambada functions.
print(repr(exc))
Now, this is going a different route in CPython
and you can see this in a GDB session, it's something like this:
Python/bltinmodule.c:builtin_repr
will call Objects/object.c:PyObject_Repr
- this function gets the PyObject *v
as the only parameter that it will use to get and call a function that implements the built-in function repr()
, BaseException_repr
in this case. This function will format the error message based on a value from args
structure field:
(gdb) p ((PyBaseExceptionObject *) self)->args
$188 = ("name 'x' is not defined",)
The args
value is set in Python/ceval.c:format_exc_check_arg
based on a NAME_ERROR_MSG
macro set in the same file.
Update: Sun 8 Nov 20:19:26 UTC 2020
test.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()
Test:
# python test.py
x
Note:
I would also recommend to watch this video from PyCon 2016.
这篇关于Python更改Exception可打印的输出,例如__builtins__重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!