【问题标题】:How can I create an Exception in Python minus the last stack frame?如何在 Python 中创建一个异常减去最后一个堆栈帧?
【发布时间】:2014-11-18 11:51:21
【问题描述】:

不确定这有多大可能,但这里是:

我正在尝试编写一个具有更微妙行为的对象 - 这可能是一个好主意,也可能不是一个好主意,我还没有确定。

我有这个方法:

def __getattr__(self, attr):                                                                                                      
    try:                                                                       
        return self.props[attr].value                                          
    except KeyError:                                                           
        pass #to hide the keyerror exception                                   

    msg = "'{}' object has no attribute '{}'"                                  
    raise AttributeError(msg.format(self.__dict__['type'], attr)) 

现在,当我像这样创建一个这样的实例时:

t = Thing()
t.foo

我得到一个包含 my 函数的堆栈跟踪:

Traceback (most recent call last):
  File "attrfun.py", line 23, in <module>
    t.foo
  File "attrfun.py", line 15, in __getattr__
    raise AttributeError(msg.format(self._type, attr))
AttributeError: 'Thing' object has no attribute 'foo'

我不希望这样 - 我希望读取堆栈跟踪:

Traceback (most recent call last):
  File "attrfun.py", line 23, in <module>
    t.foo
AttributeError: 'Thing' object has no attribute 'foo'

这是否可以通过最少的努力实现,还是需要很多?我找到了this answer,这表明某些事情看起来是可能的,尽管可能涉及。如果有更简单的方法,我很想听听!否则我就暂时搁置这个想法。

【问题讨论】:

  • 我强烈建议不要这样做。一两个月后,您将忘记您的函数在何处以及为何抛出此特定异常。
  • 如果你只想要一个自定义打印使用模块回溯,如果你想要一个干净的回溯,就让它这样。为什么要使用其他 dict 作为属性容器? self.__dict__ 已经存在。并且更改回溯并不简单,纯python不可能,你需要用ctypes破解解释器
  • @ivan_pozdeev 一方面这似乎是一件坏事,另一方面 - 我不知道为什么我会在阅读 AttributeError: 'X' has no attribute 'Y' 时感到困惑。
  • @WayneWerner 您仍然需要知道这恰好说明了什么:哪个对象是“X”以及为什么要查询它以获取“Y”(如果涉及反射,则会更加混乱)。
  • 不要忘记代码也可以自己抛出异常 - 有时,那些你意想不到的地方。

标签: python exception


【解决方案1】:

您不能篡改回溯对象(这是一件好事)。您只能控制如何处理您已经拥有的一个。

唯一的例外是:你可以

出于您的目的,要走的路似乎是第一种选择:从高于您的函数一级的处理程序重新引发异常。

而且,我再说一遍,这对您自己或任何将使用您的模块的人都是有害的,因为它会删除有价值的诊断信息。如果您出于任何理由都决心使您的模块成为专有的,那么将其作为 C 扩展来实现这一目标会更有成效。

【讨论】:

  • 这看起来像是专门用于打印错误消息 - 我有兴趣实际更改异常本身。
  • traceback 模块包含几个允许您遍历堆栈的函数。获取框架(使用tb_frame())并跳转到列表中。关于异常,您可以在本文档之后定义new one
【解决方案2】:

您可以使用 inspect 模块获取当前帧和任何其他级别。例如,当我想知道我在代码中的位置时,我会使用以下代码:

from inspect import currentframe

def get_c_frame(level = 0) :
    """
    Return caller's frame
    """
    return currentframe(level)

...
def locate_error(level = 0) :
    """
    Return a string containing the filename, function name and line
    number where this function was called.

    Output is : ('file name' - 'function name' - 'line number')
    """
    fi = get_c_frame(level = level + 2)
    return '({} - {} - {})'.format(__file__,
                               fi.f_code,
                               fi.f_lineno)

【讨论】:

  • 不过,这看起来不像我可以摆弄实际的异常?
猜你喜欢
  • 2021-08-25
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 1970-01-01
  • 2017-10-17
  • 1970-01-01
相关资源
最近更新 更多