【问题标题】:Add decorator from string从字符串添加装饰器
【发布时间】:2021-03-19 20:52:27
【问题描述】:

我有一个这样的装饰器:

def foo(func):
    """Will print the args and kwargs of a func"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('Do I have args?')
        print(args, kwargs, sep='\n')

        return func(*args, **kwargs)

    return wrapper

还有这样的“装饰师”:

def add_checks(*decorators):
    """Adds decorators to a func"""
    def check(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # how do I add here the `*decorators`?
            return func(*args, **kwargs)

        return wrapper

    return check

如何通过字符串添加装饰器?所以它是这样的:

@add_checks('foo')
def bar(a, b, c=1):
    return (a * b) / c

print(bar(5, 2, c=5))
>>> Do I have args?
>>> [5, 2]
>>> {'c': 5}
>>> 2

【问题讨论】:

  • 您是否有理由要对装饰器进行字符串索引,而不仅仅是使用内联函数引用?

标签: python python-3.x python-decorators


【解决方案1】:

你只需要遍历*decorators:

import functools


def foo(func):
    """Will print the args and kwargs of a func"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('Do I have args?')
        print(args, kwargs, sep='\n')
        #return func(*args, **kwargs)

    return wrapper


def add_checks(*decorators):
    """Adds decorators to a func"""
    def check(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for dec in decorators:
                if isinstance(dec, str):
                    # lookup for the function in globals()
                    globals()[dec](func)(*args, **kwargs)
                else:
                    dec(func)(*args, **kwargs)

            return func(*args, **kwargs)

        return wrapper

    return check


@add_checks(foo)  # reference to the function!
def bar(a, b, c=1):
    return (a * b) / c


@add_checks("foo")
def bar_strDecorated(a, b, c=1):
    return (a * b) / c


print(bar(5, 2, c=5))
print(bar_strDecorated(5, 2, c=5))

输出:

Do I have args?
(5, 2)
{'c': 5}
2.0
Do I have args?
(5, 2)
{'c': 5}
2.0

【讨论】:

  • 很好的解决方案,虽然被包装的函数不应该相互放置,而不是一个接一个地被调用?即第一个装饰器应该能够改变传递给下一个装饰器的参数/kwargs,依此类推。我很感激 OP 没有让我们参与这个系统的宏伟计划,所以我只能猜测!
  • globals 键查找看起来很奇怪,eval 实际上更适合这里吗?否则我喜欢这个解决方案
  • 我个人讨厌使用全局变量或其他方式探索代码的想法。使用函数引用(正如莫里斯所说)是正确的前进方向。但是,如果您要这样做,为什么要使用这种模式呢?只需堆叠装饰器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多