簡體   English   中英

Python 裝飾器 function 包裝器中的參數

[英]parameters in Python decorator function wrapper

對裝飾器來說相當新,這被認為是糟糕的代碼嗎? 如果是,什么是好的替代品?

import functools
def error_handaler_decorator(func):
    @functools.wraps(func)
    def wrapper(error_message_for_wrapper = None, cont = True, *args, **kwargs):
        try:
            return func(*args, **kwargs)
        except:
            if error_message_for_wraper != None:
                # Report error to user in application specific way
            if cont == True:
                return True

@error_handaler_decorator
def some_func(input_for_func):
    # Do a thing.

@error_handaler_decorator
def some_func_in_a_class(self,input):
    # Do another thing.

some_func(error_message_for_wrapper = something bad happened, input_for_func = some_input)

some_class.some_func_in_a_class(error_message_for_wrapper = something bad happened, cont = False, input_for_func = some_input)

這意味着當我調用修飾的 function 時,我必須傳遞包裝器變量,而且我認為我不能傳遞args ,只能傳遞kwargs ,但它允許我根據傳遞給 function 的內容來定義錯誤消息,而不是當我定義 function 時。

該代碼有效,(至少與我測試過的一樣多),但我的 IDE(Visual Studio 代碼)非常生氣,說:

方法調用中出現意外的關鍵字參數“error_message_for_wrapper”

我真的很想清理我的代碼,我看到的替代方法是try: except:with: try: except:使我的代碼混亂,(至少主觀上)。

With. 更好,但我寧願將我的裝飾器作為函數,它對項目更有效。

我不認為我可以with function。

好的,這將取決於我相信您使用的 Python 版本。 在 python 3 你可以這樣做:

def error_handler_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, error_message_for_wrapper = None, cont = True, **kwargs):
        try:
            return func(*args, **kwargs)
        except:
            if error_message_for_wrapper is not None:
                # Report error to user in application specific way
            if cont:
                return True
    return wrapper

在 python 2(但也適用於 python 3)中,您可以使用:

def error_handler_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        error_message_for_wrapper = kwargs.pop('error_message_for_wrapper', None)
        cont = kwargs.pop('cont', False)
        try:
            return func(*args, **kwargs)
        except:
            if error_message_for_wrapper is not None:
                # Report error to user in application specific way
            if cont:
                return True
    return wrapper

這可能是您應該使用上下文管理器而不是裝飾器的情況。

from contextlib import contextmanager


@contextmanager
def handler(msg=None, cont=True):
    try:
        yield
    except Exception:
        if msg is not None:
            print(msg)
        if not cont:
            reraise


with handler("Don't divide by zero!"):
    3/0

print("OK")

將 output

Don't divide by zero!
OK

如果您在調用handler時設置cont=False ,您將看到Don't divide by zero ,但隨后作為重新引發的異常的回溯會阻止打印OK


循環往復, contextlib還提供了一種將上下文管理器用作裝飾器的方法。 但是,您必須在沒有contextmanager幫助的情況下定義上下文管理器。

from contextlib import ContextDecorator


class handler(ContextDecorator):
    def __init__(self, msg=None, cont=True):
        self.msg = msg
        self.cont = cont

    # ContextDecorator doesn't provide default definitions,
    # so we have to provide something, even it doesn't really
    # do anything.
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, tb):
        if exc_value is not None and self.msg is not None:
            print(self.msg)

        # Returning true suppresses any exception
        # that may have been raised in the context. Returning false
        # means the exception is raised as usual.
        return self.cont


# Scolds you, but returns None
@handler("Don't divide by zero")
def some_func(x):
    return 3/x

# Scolds you *and* raises the exception
@handler("Don't divide by zero", cont=False)
def some_other_func(x):
    return 3/x

暫無
暫無

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

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