为了账号安全,请及时绑定邮箱和手机立即绑定

带参数的装饰器:没有参数时避免使用括号

带参数的装饰器:没有参数时避免使用括号

慕标琳琳 2021-06-02 18:09:47
下面是我的@logged()装饰器制造商。它的工作原理大致如下:它接受一个logger实例和一个disabled标志。如果disabled是False,则在装饰函数之前/之后输出一些日志。如果disabled是True,则它不输出任何内容并抑制logger装饰函数的 。无论是logger和disabled参数有自己的缺省值。但是,当我想使用默认值时,我仍然需要写空括号,如下所示:@logged()def foo():    pass当我只想要默认参数时,有没有办法摆脱这些空括号?这是我想要的一个例子:@loggeddef foo():    pass@logged(disabled=True)def bar():    pass@logged()装饰器制造商的代码:import loggingimport logging.configfrom functools import wrapsdef logged(logger=logging.getLogger('default'), disabled=False):    '''    Create a configured decorator that controls logging output of a function    :param logger: the logger to send output to    :param disabled: True if the logger should be disabled, False otherwise    '''    def logged_decorator(foo):        '''        Decorate a function and surround its call with enter/leave logs        Produce logging output of the form:        > enter foo          ...        > leave foo (returned value)        '''        @wraps(foo)        def wrapper(*args, **kwargs):            was_disabled = logger.disabled            # If the logger was not already disabled by something else, see if            # it should be disabled by us. Important effect: if foo uses the            # same logger, then any inner logging will be disabled as well.            if not was_disabled:                logger.disabled = disabled            logger.debug(f'enter {foo.__qualname__}')            result = foo(*args, **kwargs)            logger.debug(f'leave {foo.__qualname__} ({result})')            # Restore previous logger state:            logger.disabled = was_disabled            return result        return wrapper    return logged_decoratorlogging.config.dictConfig({    'version': 1,    'formatters': {        'verbose': {            'format': '%(asctime)22s %(levelname)7s %(module)10s %(process)6d %(thread)15d %(message)s'        }        , 'simple': {            'format': '%(levelname)s %(message)s'        }    }
查看完整描述

3 回答

?
梦里花落0921

TA贡献1772条经验 获得超6个赞

它支持两种开发风格:嵌套(如在 python 装饰器工厂中)和平面(少一层嵌套)。这是您的示例在平面模式下的实现方式:


from decopatch import function_decorator, DECORATED

from makefun import wraps


@function_decorator

def logged(disabled=False, logger=logging.getLogger('default'), func=DECORATED):


    # (1) create a signature-preserving wrapper

    @wraps(func)

    def _func_wrapper(*f_args, **f_kwargs):

        # stuff

        result = func(*f_args, **f_kwargs)

        # stuff

        return result


    # (2) return it

    return _func_wrapper

请注意,我使用makefun.wraps而不是functools.wraps此处,以便完全保留签名(如果参数无效,则根本不会调用包装器)。


decopatch支持另一种开发风格,我称之为double-flat,专门用于创建这样的签名保留函数包装器。您的示例将像这样实现:


from decopatch import function_decorator, WRAPPED, F_ARGS, F_KWARGS


@function_decorator

def logged(disabled=False, logger=logging.getLogger('default'), 

           func=WRAPPED, f_args=F_ARGS, f_kwargs=F_KWARGS):

    # this is directly the signature-preserving wrapper

    # stuff

    result = func(*f_args, **f_kwargs)

    # stuff

    return result

您可以检查两种样式是否按预期工作:


@logged(disabled=True)

def foo():

    pass


@logged

def bar():

    pass


foo()


bar()

请查看文档以获取详细信息。


查看完整回答
反对 回复 2021-06-08
?
POPMUISE

TA贡献1765条经验 获得超5个赞

或者使用部分(在 Python 食谱中找到的解决方案:9.6)


from functools import wraps, partial


def foo(func=None, *, a=None, b=None):

    if func is None:

        return partial(foo, a=a, b=b)


    @wraps(func)

    def wrapper(*args, **kwargs):

        return func(*args, **kwargs)

    return wrapper


查看完整回答
反对 回复 2021-06-08
  • 3 回答
  • 0 关注
  • 202 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号