gpt4 book ai didi

从 stacktrace 中隐藏装饰器的 Python 2 和 3 兼容方式

转载 作者:太空宇宙 更新时间:2023-11-04 01:17:03 25 4
gpt4 key购买 nike

我写了一个我不想在堆栈跟踪中显示的装饰器。所以在 Python2 中我会这样做:

class SneakyDecorator(object):
def __init__(self, f):
self.f = f

def __call__(self, *args, **kwargs):
# [...]
try:
self.f(*args, **kwargs)
except:
t, v, tb = sys.exc_info()
raise v, None, tb.tb_next # <=== Important line

在 Python3 中我会这样做:

class SneakyDecorator:
def __init__(self, f):
self.f = f

def __call__(self, *args, **kwargs):
# [...]
try:
self.f(*args, **kwargs)
except:
t, v, tb = sys.exc_info()
raise v.with_traceback(tb.tb_next) # <=== Important line

所以问题来了:有什么方法可以同时兼容 Python2 和 Python3 吗?我更喜欢不涉及两个独立代码库的解决方案。

我尝试使用 six 模块的 reraise 函数,但问题是,该函数随后出现在堆栈跟踪中。

同样的问题,如果你像在这个答案中那样做:Exception with original traceback - 2.6-3.X compatible version .

更新:Python3 代码不起作用!调用方法仍然显示在堆栈跟踪中。所以后续问题是:有没有办法在 Python3 中做到这一点?

最佳答案

使这项工作有效的唯一方法是保持 __call__ 方法的不同版本,因为 exec 本身会创建一个堆栈框架!以下,在 Python 2 中再次显示框架:

class SneakyDecorator:
def __init__(self, f):
self.f = f

def __call__(self, *args, **kwargs):
# [...]
try:
self.f(*args, **kwargs)
except:
t, v, tb = sys.exc_info()
exec("raise v, None, tb.tb_next")

结果:

>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 12, in __call__
File "<stdin>", line 3, in f
ValueError: Oi!

所以使用:

def __call__(self, *args, **kwargs):
# [...]
try:
self.f(*args, **kwargs)
except:
t, v, tb = sys.exc_info()
if sys.version_info[0] <= 2:
exec("raise v, None, tb.tb_next")
else:
raise v.with_traceback(tb.tb_next)

实际上不会工作。

对于 Python 2,以下内容与您的两个独立类具有完全相同的功能:

if sys.version_info[0] <= 2:
_call = '''\
def _call(self, *args, **kwargs):
# [...]
try:
self.f(*args, **kwargs)
except:
t, v, tb = sys.exc_info()
raise v, None, tb.tb_next
'''
exec(_call)
else:
def _call(self, *args, **kwargs):
# [...]
try:
self.f(*args, **kwargs)
except:
t, v, tb = sys.exc_info()
raise v.with_traceback(tb.tb_next)


class SneakyDecorator:
def __init__(self, f):
self.f = f

__call__ = _call
# niceties, patch up name and qualified name. Optional.
__call__.__name__ = '__call__'
__call__.__qualname__ = 'SneakyDecorator.__call__'

但是,请注意,对于 Python 3,Exception.with_traceback() 方法可能允许您在删除当前帧的情况下附加一个新的回溯,但 Python 会将其添加回去 在您重新引发异常的那一刻!

关于从 stacktrace 中隐藏装饰器的 Python 2 和 3 兼容方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23765707/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com