簡體   English   中英

如何在裝飾器中捕獲異常

[英]How to catch an exception in a decorator

我有一個函數,我的原因異常,我希望它成為裝飾器。 代碼如下:

def des(i):
    def new_func(func):
        if i == 1:
            raise Exception
        else:
            return func
    return new_func


@des(1)
def func():
    print "!!"


if __name__ == '__main__':
    try:
        func()
    except Exception:
        print 'error'

但輸出是:

Traceback (most recent call last):
  File "D:/des.py", line 10, in <module>
    @des(1)
  File "D:/des.py", line 4, in new_func
    raise Exception
Exception

因此,如何捕獲此異常?

定義函數時會引發異常。 捕獲此異常的唯一方法是:

try:
    @des(1)
    def func():
        print '!!'
except:
    print 'error'

如果這引起異常的原因令人困惑,請記住您的代碼等效於:

def func():
    print '!!'
func = des(1)(func)
# des(1) = new_func, so des(1)(func) is new_func(func)

因此,現在您的代碼基本上可以歸結為:

_des = des(1)

def _func();
    print '!!'

func = _des(func)

您使用des的返回值作為裝飾器,我認為這是造成問題的原因。

我想您可能想再嵌套一次返回的函數:

def des(i): # container func.
    def new_func(func):
        def ret_func(*args, **kwargs):
            if i == 1:
                raise Exception
            else:
                return func(*args, **kwargs)

        return ret_func # return the func with the bound variable
    return new_func # return the func which creates the function w/ the bound var.


@des(1)
def func():
    print "!!"

我在這里缺少一個功能級別。

企業

import functools
def des(i): # this is the "decorator creator", called with des(1)
    def deco(func): # this is returned and is the real decorator, called at function definition time
        @functools.wraps(func) # sugar
        def new_func(*a, **k): # and this is the function called on execution.
            if i == 1:
                raise Exception # I hope this is just for testing... better create a new exception for this
            else:
                return func(*a, **k)
        return new_func
    return deco

@des(1)
def func():
    print "!!"

if __name__ == '__main__':
    try:
        func()
    except Exception:
        print 'error'

正如其他答案所解釋的那樣,當前的問題是,在將裝飾器應用於函數時(而不是在調用函數時)引發了異常。

要解決此問題,您需要使裝飾器返回一個進行異常引發的函數。 這是可能的工作方式:

import functools

def des(i):
    def decorator(func):
        if i != 1:
            return func # no wrapper needed

        @functools.wraps(func)
        def raiser(*args, **kwargs):
            raise Exception

        return raiser

    return decorator

des功能是一個“裝飾工廠”。 除了提供一個范圍來保存返回的裝飾器的i參數外,它實際上並沒有做任何其他事情。

decorator功能進行檢查,看是否需要做一些特殊的事情。 如果不是,則返回修飾后的函數,不做修改。 如果i==1 ,則返回自定義函數。

如果i==1raiser函數是裝飾器的返回值。 總是在調用時引發異常。 functools.wraps適用於它的裝飾是不是絕對必要的,但它使得它看起來更像原來的功能(同__name____doc__等)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM