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

如何在Python中创建减去最后一个堆栈帧的异常?,python,exception,Python,Exception,不确定这有多可能,但这里有: 我试图写一个行为稍微微妙的对象——这可能是个好主意,也可能不是个好主意,我还没有决定 我有这个方法: def __getattr__(self, attr): try:

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

我试图写一个行为稍微微妙的对象——这可能是个好主意,也可能不是个好主意,我还没有决定

我有这个方法:

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
我得到一个stacktrace,其中包含我的函数:

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'
回溯(最近一次呼叫最后一次):
文件“attrfun.py”,第23行,在
t、 福
文件“attrfun.py”,第15行,在__
raise AttributeError(消息格式(self.\u类型,attr))
AttributeError:“Thing”对象没有属性“foo”
我不希望这样-我希望堆栈跟踪读取:

Traceback (most recent call last):
  File "attrfun.py", line 23, in <module>
    t.foo
AttributeError: 'Thing' object has no attribute 'foo'
回溯(最近一次呼叫最后一次):
文件“attrfun.py”,第23行,在
t、 福
AttributeError:“Thing”对象没有属性“foo”

这是可能的,用最少的努力,还是有很多需要?我发现这表明有些事情看起来是可能的,尽管可能有牵连。如果有更简单的方法,我很想听!否则,我现在就把这个想法放在架子上。

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

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

唯一的例外是:你可以

  • 用另一个异常替换一个异常,或用
    raise e
    重新引发它(即使回溯点指向re-raise语句的位置)
  • (这反映了回溯对象的洋葱状结构)
出于您的目的,该方法似乎是第一个选项:从比函数高一级的处理程序重新引发异常


而且,我要再说一遍,这对你自己或任何使用你的模块的人都是有害的,因为它会删除有价值的诊断信息。如果您死心塌地地想让您的模块成为专有模块,那么将其作为C扩展将更有效率。

我强烈建议您不要这样做。一两个月后,您将忘记函数引发此特定异常的位置和原因。如果您只需要自定义打印,请使用模块回溯,如果您需要干净的回溯,请这样做。为什么使用其他dict作为属性容器?self.\uuuu dict\uuuuuu已经存在。更改回溯并不简单,纯python也不可能做到这一点,您需要使用ctypes@ivan_pozdeev一方面,这似乎是件坏事,另一方面-我不知道为什么在阅读
AttributeError时会感到困惑:'X'没有属性'Y'
@WayneWerner您仍然需要知道这发生在哪里:哪个对象是'X'以及为什么要查询'Y'(如果涉及反射,会造成额外的困惑)。别忘了代码本身可以引发异常,太-有时,这些都是你从未预料到的。但是,这看起来并不是我真的可以处理实际的异常?这看起来是专门用于打印错误消息的-我感兴趣的是实际更改异常本身。该模块包含几个函数,允许你遍历堆栈。获取帧(使用)并跳入列表。关于例外情况,您可以在以下文档中定义一个。