Major
Major

Reputation: 199

Add a function using another function's parameter declaration

I am trying to add some customized logic outside of an existing function. Here are the example:

# existing function that I cannot change
def sum(a, b, c, d):
  return a+b+c+d

# the function I want to build
def sumMultiply(a, b, c, d, multiplier):
  return multiplier * sum(a, b, c, d)

This is a stupid example, but essentially I want to build a new function that takes all the parameter of the existing function and add a few new arguments.

The above solution is problematic when the existing function changes its definition. For example:

# in some updates the original function dropped one parameter
def sum(a, b, c):
  return a+b+c

# the new function will give an error since there is no parameter "d"
def sumMultiply(a, b, c, d, multiplier):
  return multiplier * sum(a, b, c, d) # error

How can I specify the new function so that I do not need to worry about changing the new function definition when the existing function definition changes?

Upvotes: 1

Views: 63

Answers (3)

ogdenkev
ogdenkev

Reputation: 2374

I would create a decorator function

def create_fun_multiplier(fun, multiplier=1):
    def multiplier_fun(*args):
        return multiplier * fun(*args)
    return multiplier_fun

def my_sum(a, b, c):
    return a + b + c

sumMultiply = create_fun_multiplier(my_sum, multiplier=2)
print(sumMultiply(3, 4, 7))

Upvotes: 1

Hitobat
Hitobat

Reputation: 3037

I would look at using keyword args for this problem.

eg.

def sum(a, b, c):
    return a + b + c

def sumMultiply(*args, multiplier=1):
    return multiplier * sum(*args)

Upvotes: 0

decorator-factory
decorator-factory

Reputation: 3083

One way would be to use arbitrary positional or keyword arguments:

def sumMultiply(multiplier, *numbers):
    return multiplier * sum(*numbers)

def sumMultiply(multiplier, *args, **kwargs):
    return multiplier * sum(*args, **kwargs)

However, if you see yourself passing around the same set of data around, consider making a parameter object. In your case, it can simply be a list:

def sum(numbers):
    ...

def sumMultiply(multiplier, numbers):
    return multiplier * sum(numbers)

There are some additional downsides to using arbitrary arguments:

  • the arguments are implicit: you might need to dig through several layers to see what you actually need to provide
  • they don't play well with type annotations and other static analysers (e.g. PyCharm's refactorings)

Upvotes: 2

Related Questions