为什么 Python 中的装饰器风格的上下文管理器在 Tkinter window 中没有捕获异常?
Why decorator-style context manager in Python doesn't catch exception within Tkinter window?
有一个简单的代码,其中包含装饰器通过 contextlib 生成的上下文管理器。当我按下按钮时引发异常并且不由上下文管理器处理。为什么会这样?
from Tkinter import Tk, Button
from contextlib import contextmanager
def close_window():
window.destroy()
raise Exception
@contextmanager
def safe():
try:
yield
except:
print 'Exception catched'
with safe():
window = Tk()
button = Button(window, text='Press me', command=close_window)
button.pack()
window.mainloop()
为什么仍然会引发异常?
UPD 我用 Python 2.7
Tkinter 主进程循环不会因异常而中断,也不会进一步传播它们。因此,异常永远不会到达 with
语句(因为 tkinter 本身捕获并报告异常然后停止执行)。
您将需要创建一个装饰器来捕获这些异常并记录它们或执行您想要执行的任何逻辑。
例子-
from Tkinter import Tk, Button
from contextlib import contextmanager
class exceptioncatcher: # <---the decorator
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
try:
return self.function(*args, **kwargs)
except Exception:
print 'Exception catched1'
@exceptioncatcher
def close_window():
window.destroy()
raise Exception
@contextmanager
def safe():
try:
yield
except Exception:
print 'Exception catched'
with safe():
window = Tk()
button = Button(window, text='Press me', command=close_window)
button.pack()
window.mainloop()
使用上面的代码,当我点击 Press
按钮时,它会为我记录 Exception catched1
并退出。
另外,做 except:
不好,你应该给出你想捕获的异常(或至少 except Exception:
)。
有一个简单的代码,其中包含装饰器通过 contextlib 生成的上下文管理器。当我按下按钮时引发异常并且不由上下文管理器处理。为什么会这样?
from Tkinter import Tk, Button
from contextlib import contextmanager
def close_window():
window.destroy()
raise Exception
@contextmanager
def safe():
try:
yield
except:
print 'Exception catched'
with safe():
window = Tk()
button = Button(window, text='Press me', command=close_window)
button.pack()
window.mainloop()
为什么仍然会引发异常?
UPD 我用 Python 2.7
Tkinter 主进程循环不会因异常而中断,也不会进一步传播它们。因此,异常永远不会到达 with
语句(因为 tkinter 本身捕获并报告异常然后停止执行)。
您将需要创建一个装饰器来捕获这些异常并记录它们或执行您想要执行的任何逻辑。
例子-
from Tkinter import Tk, Button
from contextlib import contextmanager
class exceptioncatcher: # <---the decorator
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
try:
return self.function(*args, **kwargs)
except Exception:
print 'Exception catched1'
@exceptioncatcher
def close_window():
window.destroy()
raise Exception
@contextmanager
def safe():
try:
yield
except Exception:
print 'Exception catched'
with safe():
window = Tk()
button = Button(window, text='Press me', command=close_window)
button.pack()
window.mainloop()
使用上面的代码,当我点击 Press
按钮时,它会为我记录 Exception catched1
并退出。
另外,做 except:
不好,你应该给出你想捕获的异常(或至少 except Exception:
)。