如何在Python中向装饰器传递特定参数

3 投票
2 回答
2987 浏览
提问于 2025-04-16 00:38

我想写一个Python的函数装饰器,用来检查某些函数的参数是否符合特定的条件。比如说,我想检查某些参数是否总是偶数,那么我希望能像这样使用(这不是有效的Python代码)

def ensure_even( n )  :
  def decorator( function ) :
    @functools.wraps( function )
    def wrapper(*args, **kwargs):
      assert(n % 2 == 0)
      return function(*args, **kwargs)
    return wrapper
   return decorator


@ensure_even(arg2)
def foo(arg1, arg2, arg3) : pass

@ensure_even(arg3)
def bar(arg1, arg2, arg3) : pass

但是我不知道怎么实现上面的功能。有没有办法把特定的参数传给装饰器?(就像上面提到的foo的arg2和bar的arg3)

谢谢!

2 个回答

4

我之前的回答没有抓住你问题的重点。

这里有一个更详细的解决方案:

def ensure_even(*argvars):
  def fdec(func):
    def f(*args,**kwargs):
      for argvar in argvars:
        try:
          assert(not args[func.func_code.co_varnames.index(argvar)] % 2)
        except IndexError:
          assert(not kwargs[argvar] % 2)
      return func(*args,**kwargs)
    return f
  return fdec

这是使用方法:

@ensure_even('a','b')
def both_even(a,b):
    print a,b

@ensure_even('even')
def first_even(even, arg2):
    print even, arg2

both_even(2,2)
first_even(2,3)
both_even(2,1) #fails

不过我不确定它在所有情况下都能奏效。

11

你可以这样做:

def ensure_even(argnum):
  def fdec(func):
    def f(*args, **kwargs):
      assert(args[argnum] % 2 == 0)  #or assert(not args[argnum] % 2)
      return func(*args, **kwargs)
    return f
  return fdec

那么:

@ensure_even(1)  #2nd argument must be even
def test(arg1, arg2):
  print(arg2)

test(1,2) #succeeds
test(1,3) #fails

撰写回答