当前位置: 首页 > 面试题库 >

如何创建可以使用或不使用参数的Python装饰器?

宰父远
2023-03-14
问题内容

我想创建一个可以与参数一起使用的Python装饰器:

@redirect_output("somewhere.log")
def foo():
    ....

或不使用它们(例如,默认情况下将输出重定向到stderr):

@redirect_output
def foo():
    ....

那有可能吗?

请注意,我并不是在寻找重定向输出问题的其他解决方案,这只是我想要实现的语法的一个示例。


问题答案:

我知道这个问题很旧,但是有些评论是新的,尽管所有可行的解决方案本质上都是相同的,但大多数解决方案都不是很干净也不易于阅读。

就像thobe的回答所说,处理这两种情况的唯一方法是检查这两种情况。最简单的方法是简单地检查是否有单个参数并且它是callabe(注意:如果您的装饰器仅接受1个参数并且恰好是一个可调用对象,则需要额外检查):

def decorator(*args, **kwargs):
    if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
        # called as @decorator
    else:
        # called as @decorator(*args, **kwargs)

在第一种情况下,您可以执行任何普通装饰器所执行的操作,返回传入函数的修改或包装版本。

在第二种情况下,您返回一个“新”修饰符,该修饰符以某种方式使用通过 args,* kwargs传递的信息。

一切都很好,但是必须为您制作的每个装饰器将其写出来,这会很烦人,而不是那么干净。取而代之的是,能够自动修改我们的装饰器而不必重新编写它们,这将是很好的……但这就是装饰器的作用!

使用以下装饰器装饰器,我们可以对装饰器进行装饰,以便可以使用带参数或不带参数的装饰器:

def doublewrap(f):
    '''
    a decorator decorator, allowing the decorator to be used as:
    @decorator(with, arguments, and=kwargs)
    or
    @decorator
    '''
    @wraps(f)
    def new_dec(*args, **kwargs):
        if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
            # actual decorated function
            return f(args[0])
        else:
            # decorator arguments
            return lambda realf: f(realf, *args, **kwargs)

    return new_dec

现在,我们可以使用@doublewrap装饰我们的装饰器,它们将在有或无参数的情况下工作,但有一个警告:

我在上面提到过,但是应该在这里重复一遍,此装饰器中的检查对装饰器可以接收的参数进行了假设(即,它无法接收单个可调用的参数)。由于我们现在使它适用于任何生成器,因此需要牢记或修改它,以防矛盾。

下面演示其用法:

def test_doublewrap():
    from util import doublewrap
    from functools import wraps

    @doublewrap
    def mult(f, factor=2):
        '''multiply a function's return value'''
        @wraps(f)
        def wrap(*args, **kwargs):
            return factor*f(*args,**kwargs)
        return wrap

    # try normal
    @mult
    def f(x, y):
        return x + y

    # try args
    @mult(3)
    def f2(x, y):
        return x*y

    # try kwargs
    @mult(factor=5)
    def f3(x, y):
        return x - y

    assert f(2,3) == 10
    assert f2(2,5) == 30
    assert f3(8,1) == 5*7


 类似资料:
  • 问题内容: 我想制作一个可以使用或不使用参数的装饰器: 在我的代码中,只有使用带参数的decorator才有效:如何使两者同时起作用(带有和不带有参数)? 问题答案: 我找到一个示例,您可以使用或:不错!

  • 问题内容: 我有一个带几个参数的Python函数。在某些情况下,可以忽略其中一些参数。 这些参数通过是字符串,每个都有不同的含义。我可以选择要以任何组合形式传递的可选参数,这一点很重要。例如,或,,或,或所有它们(这些是我的选择)。 如果我可以重载该函数,那就太好了-但我读到Python不支持重载。我试图在列表中插入一些必需的int参数-并收到参数不匹配错误。 现在,我正在发送空字符串来代替前几个

  • 问题内容: 我想定义一些通用装饰器,以在调用某些函数之前检查参数。 就像是: 旁注: 类型检查只是在这里显示一个示例 我正在使用Python 2.7,但是Python 3.0也会很有趣 问题答案: 从装饰器的功能和方法: Python 2 Python 3 在Python 3中已更改为,并且已更改为。 用法: 可以是或

  • 在MobX 中使用 ES.next 装饰器是可选的。本章节将解释如何(避免)使用它们。 使用装饰器的优势: 样板文件最小化,声明式代码。 易于使用和阅读。大多数 MobX 用户都在使用。 使用装饰器的劣势: ES.next 2阶段特性。 需要设置和编译,目前只有 Babel/Typescript 编译器支持。 启用装饰器 如果想使用装饰器,请按照以下步骤操作。 TypeScript 启用 tsco

  • 问题内容: 我正在尝试创建一个以验证以下日期时间: 我已经尝试使用以下日期时间格式化程序来验证上述日期: 它适用于所有上述日期罚款,但根据我的要求就应该失败的。 注意:我知道使用以下格式化程序可以达到预期的结果: 但是我想知道,通过改变我们可以达到预期的结果吗? 为了解析日期,我使用以下方法: 问题答案: 您必须创建一个可选部分(使用和方法),该部分包含小数点后跟1至6位数字: 这将从解析,并引发

  • 问题内容: 我已经看到许多Python装饰器的示例,它们是: 函数样式修饰符(包装函数) 类风格装饰(实施,和) 不带参数的装饰器 带参数的装饰器 “方法友好”的装饰器(即可以装饰类中的方法) “功能友好”的装饰器(可以装饰普通功能 可以装饰方法和功能的装饰器 但是我从未见过一个可以完成上述所有操作的示例,而且我无法从各种答案到特定问题,这个或这个上看到过,如何结合以上所有内容。 我想要的是一个