Python更改Exception可打印的输出,例如__builtins__重载 [英] Python change Exception printable output, eg overload __builtins__

查看:82
本文介绍了Python更改Exception可打印的输出,例如__builtins__重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种将Exception的可打印输出更改为愚蠢消息的方法,以便进一步了解python内部信息(并与朋友;混乱),

考虑以下代码

  try:x#未定义除了NameError作为exc:打印(EXC) 

代码应输出未定义名称'x'

我希望将输出为您建议的名称'x'的更改尚未定义,我的主.提高您的编码技能.

到目前为止,我了解到您无法更改 __ builtins __ ,因为它们已经烘焙"到了作为C代码,除非:

  1. 您使用forbiddenfruit.curse方法来添加/更改任何对象的属性
  2. 您手动覆盖对象的字典

我尝试过两种解决方案,但都没有成功:

禁果解决方案:

 从禁果进口诅咒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:

  1. You use forbiddenfruit.curse method which adds / changes properties of any object
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆