【问题标题】:Using a decorator to check for optional arguments使用装饰器检查可选参数
【发布时间】:2014-10-15 05:40:45
【问题描述】:

我正在尝试弄清楚如何编写一个装饰器来检查函数是否是使用特定的可选参数调用的。这可能不是检查参数的pythonic方式,但无论如何我都想知道使用装饰器的解决方案。这是我正在寻找的示例:

@require_arguments("N", "p")  # Question here

def g(x,*args,**kwargs):
    if "N" not in kwargs: raise SyntaxError("missing N")
    if "p" not in kwargs: raise SyntaxError("missing p")
    print x

g(3,N=2) # Raise "missing p"

如何编写会引发相应错误的装饰器@require_arguments(*args)?

【问题讨论】:

  • "... 引发 适当的错误" 可能是 TypeError,因为这是 Python 因函数调用中缺少参数而引发的异常?

标签: python decorator optional-parameters python-decorators


【解决方案1】:

dano的回答是正确的,我能补充的唯一建议是:

  • 使用functools.wraps 创建装饰器,这样函数的名称及其文档字符串将被保留。

  • 生成所有缺失参数的列表,而不是单个参数。我个人讨厌编译器只是说:'you forgot a',然后当我添加它时它仍然抱怨:'you forgot b' 等等。 p>

装饰器变成:

from functools import wraps

def require_arguments(*reqs):
    def decorator(func):
        @wraps(func)
        def decorated(*args, **kwargs):
            missing = [req for req in reqs if req not in kwargs]
            if missing:
                raise TypeError('missing ' + ', '.join(missing))
            return func(*args, **kwargs)
        return decorated
    return decorator

示例

@require_arguments('N', 'p')
def g(x, *args, **kargs):
    """just return x"""
    print x

print g.__name__
print g.__doc__

try:
    print g(3)
except TypeError as e:
    print e

输出

g
just return x
missing N, p

更好的方法

如果您需要所需的参数,只需明确要求它们,例如:def g(x, N, p)。您仍然可以调用 g(x=2, N=5, p=3) 之类的函数,以使您的代码更具表现力,即使您指定参数时顺序不同。但是您将拥有一个固定的 api(这通常很好),您将能够指定参数或使用固定的 api 顺序。

def f(a, b, c):
    print a, b, c

f(1, 2, 3)            # 1 2 3
f(c=1, b=2, a=3)      # 3 2 1

【讨论】:

    【解决方案2】:

    给你:

    def require_arguments(*reqargs):
        def decorator(func):
            def wrapper(*args, **kwargs):
                for arg in reqargs:
                    if not arg in kwargs:
                        raise TypeError("Missing %s" % arg)
                return func(*args, **kwargs)
            return wrapper
        return decorator
    
    @require_arguments("N", "p")  # Question here
    def g(x,*args,**kwargs):
        print x
    
    g(3,N=2) # Raise "missing p"
    

    输出:

    Traceback (most recent call last):
      File "arg.py", line 19, in <module>
        g(3,N=2) # Raise "missing p"
      File "arg.py", line 7, in wrapper
        raise ValueError("Missing %s" % arg)
    ValueError: Missing p
    

    【讨论】:

    • 完美,谢谢!关于@SylvainLeroux,你认为应该改成TypeError吗?
    • @Hooked 是的,TypeError 可能更合适。
    猜你喜欢
    • 2014-11-03
    • 1970-01-01
    • 2021-04-14
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 2014-03-27
    • 2011-04-25
    相关资源
    最近更新 更多