How to pass specific argument to decorator in python

I want to write a python function decorator that checks that some arguments to a function pass some criteria. For example, suppose I want to check that some arguments are always even, then I want to be able to do something like this (invalid python code)

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

But I can’t figure out how to achieve this. Is there a way to pass specific arguments to the decorator? (e.g. arg2 for foo and arg3 for the bar above)

Thank!

+3
source share
2 answers

You can do it:

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

So then:

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

test(1,2) #succeeds
test(1,3) #fails
+11
source

My previous answer missed the point of your question.

Here's a longer solution:

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

, .

+4

Source: https://habr.com/ru/post/1752512/


All Articles