Eran Witkon
Eran Witkon

Reputation: 4092

How to use a decorator to send arguments to a function in python

I have a set of functions in python that gets the same 2 parameters + other parameters.

def myMethodA (param1, param2, specificParm)
    do code

 def myMethodB (param1, param2, specificParm1 specificParam2)
    do code

I waned to create a decorator that replace the need to call with the first 2 parameters by pushing the parameters before calling the function:

@withParams()
def myMethodA (specificParam)
        do code

But if I omit the parameters then the decorator can't call it either and if I leave them then the caller need to specify them as well.

anyway to solve this? Can I do something with args* but still have named parameters for specificParam? Also, How can I reference param1 and param2 inside myMethodA

Upvotes: 3

Views: 1417

Answers (4)

Ruud de Jong
Ruud de Jong

Reputation: 784

Sounds like you need functools.partial, to pre-populate the "constant" parameters:

>>> from functools import partial

>>> def myMethodA(param1, param2, specificParm):
        print("myMethodA(", param1, param2, specificParm, ")")

>>>> def myMethodB (param1, param2, specificParm1, specificParam2):
        print("myMethodB(", param1, param2, specificParm1, specificParam2, ")")

>>> preMethodA = partial(myMethodA, "p1", "p2")
>>> preMethodB = partial(myMethodB, "p1", "p2")
>>> preMethodA(34)
myMethodA( p1 p2 34 )
>>> preMethodB(8, 9)
myMethodB( p1 p2 8 9 )

Upvotes: 0

Mark Tolonen
Mark Tolonen

Reputation: 177481

It sounds like you may want functools.partial. It returns a new function with some parameters already specified:

import functools

def withParams(func):
    return functools.partial(func,1,2)

@withParams
def myMethodA (param1, param2, specificParam):
    print(param1,param2,specificParam)

@withParams
def myMethodB (param1, param2, specificParam1, specificParam2):
    print(param1,param2,specificParam1, specificParam2)

myMethodA(10)
myMethodB(12,13)
1 2 10
1 2 12 13

Upvotes: 1

aghast
aghast

Reputation: 15300

I'd recommend you go old school, and just reassign the names using functools.partial:

# module foo

def func1(common_1, common_2, specific_1):
    pass

def func2(common_1, common_2, specific_2, specific_3):
    pass

Then elsewhere (or lower in the file, if you like) you can do this:

import functools

import foo

common_args = (1, 'fred')
foo.func1 = functools.partial(foo.func1, *common_args)
foo.func2 = functools.partial(foo.func2, *common_args)

# ...

foo.func1('special')

foo.func2('equally special', 'but different')

Upvotes: 0

Moses Koledoye
Moses Koledoye

Reputation: 78546

You can add those two parameters when you call the function in the decorator's wrapper function as part of the kwargs. All decorated functions will automatically have those two parameters passed as keyword arguments before making the call:

def withParams(func):
    def wrapper(*args, **kwargs):
        kwargs['param1'] = 1
        kwargs['param2'] = 2
        return func(*args, **kwargs)
    return wrapper

@withParams
def add(specificparam, *args, **kwargs):
      print(specificparam)  # 3
      print(args)           # (4,)
      print(kwargs)         # {'param2': 2, 'param1': 1}
      return specificparam + sum(args) + sum(kwargs.values())

print(add(3,4)) # 10

You can drop the args part if all you'll be passing from the main function call are the specific parameters for each function.

Upvotes: 0

Related Questions