如何在Python中创建一个Exception减去最后一个堆栈帧?

时间:2014-11-18 11:51:21

标签: python exception

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

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

我有这个方法:

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表明看起来有可能,尽管可能涉及到了。如果有一种更简单的方法,我很乐意听到它!否则我现在就把这个想法放在架子上。

2 个答案:

答案 0 :(得分:3)

你不能篡改追溯对象(这是一件好事)。你只能控制你处理的方式。

唯一的例外是:你可以

出于您的目的,前进的方式似乎是第一个选项:从功能上方一级处理器重新引发异常。

而且,我会再次这样说,这对您自己或任何将使用您的模块的人都有害,因为它会删除有价值的诊断信息。如果你已经决定使你的模块具有任何基本原理的专有权,那么将它作为C扩展的目标更有效率。

答案 1 :(得分:0)

您可以使用 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)