Python装饰函数包装器中的参数

问题描述 投票:0回答:1

相当新的装修人员,这算不算是坏代码?如果是,有什么好的替代方法?

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)

这意味着我在调用装饰函数时必须传递封装变量,我认为不能传递 args惟有 kwargs但它允许我根据我传递给函数的内容来定义错误信息,而不是在我定义函数的时候。

这段代码可以工作,(至少在我测试过的范围内),但是我的IDE(Visual Studio代码)非常生气,说:"在方法调用中,意外的关键字参数'error_message_for_wrapper'。

在方法调用中,意外的关键字参数'error_message_for_wrapper'。

我真的想清理我的代码,我看到的替代方案是 try: except:with:. try: except: 让我的代码变得很乱,(至少主观上是这样)。

With. 是更好的,但我更愿意把我的装饰符作为函数,这对项目来说更好。

我不认为我可以有 with 作为一个函数。

python python-decorators
1个回答
0
投票

好吧,这将取决于你使用的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

0
投票

这可能是一个你应该使用上下文管理器而不是装饰器的例子。

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")

将输出

Don't divide by zero!
OK

如果你设置 cont=False 当你打电话 handler,你会看到 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
© www.soinside.com 2019 - 2024. All rights reserved.