Python function pointer with different arguments - python

I have defined three functions.
def evaluate1(a, b):
pass
def evaluate2(a, b):
pass
def evaluate3(a, b, c):
pass
What I want to do use a pointer to record which evaluate function I will use depending on the test inputs. The logic is as shown follows:
def test(a, b, c, d):
# let evaluate_function records which evaluate function I will use
if c > 1:
evaluate_function = evaluate3 # not sure
else:
if d:
evaluate_function = evaluate1
else:
evaluate_function = evaluate2
# execute the evaluate function
evaluate_function(a, b, ?)
However, since evaluate3 has different arguments from evaluate1 and evaluate3. How should I do? Thanks!

You have come up with a good idea of using a 'function pointer' to select the function. But since you know which function you are selecting at the time, you could also bind up the params:
def test(a, b, c, d):
# let evaluate_function records which evaluate function I will use
if c > 1:
evaluate_function = evaluate3 # not sure
params = a,b,d
else:
if d:
evaluate_function = evaluate1
params = a,b
else:
evaluate_function = evaluate2
params = a,c
# execute the evaluate function
evaluate_function(*params)
I'll leave it to you to properly select the params.

Why not just call the evaluate functions directly instead of assigning them to a function as so. Makes it more readable
def evaluate1(a, b):
print('evaluate1')
def evaluate2(a, b):
print('evaluate2')
def evaluate3(a, b, c):
print('evaluate3')
def test(a, b, c=None, d=None):
# let evaluate_function records which evaluate function I will use
if c and c > 1:
evaluate3(a, b, c)
else:
if d:
evaluate1(a, b)
else:
evaluate2(a, c)
test(1,2,c=0.1,d=1)
#evaluate1
test(1,2)
#evaluate2
test(1,2,3)
#evaluate3

Related

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?
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)
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))
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)

How would I run a function given its name?

I have a large number of blending functions:
mix(a, b)
add(a, b)
sub(a, b)
xor(a, b)
...
These functions all take the same inputs and provide different outputs, all of the same type.
However, I do not know which function must be run until runtime.
How would I go about implementing this behavior?
Example code:
def add(a, b):
return a + b
def mix(a, b):
return a * b
# Required blend -> decided by other code
blend_name = "add"
a = input("Some input")
b = input("Some other input")
result = run(add, a, b) # I need a run function
I have looked online, but most searches lead to either running functions from the console, or how to define a function.
I'm not really big fan of using dictionary in this case so here is my approach using getattr. although technically its almost the same thing and principle is also almost the same, code looks cleaner for me at least
class operators():
def add(self, a, b):
return (a + b)
def mix(self, a, b):
return(a * b)
# Required blend -> decided by other code
blend_name = "add"
a = input("Some input")
b = input("Some other input")
method = getattr(operators, blend_name)
result = method(operators, a, b)
print(result) #prints 12 for input 1 and 2 for obvious reasons
EDIT
this is edited code without getattr and it looks way cleaner. so you can make this class the module and import as needed, also adding new operators are easy peasy, without caring to add an operator in two places (in the case of using dictionary to store functions as a key/value)
class operators():
def add(self, a, b):
return (a + b)
def mix(self, a, b):
return(a * b)
def calculate(self, blend_name, a, b):
return(operators.__dict__[blend_name](self, a, b))
# Required blend -> decided by other code
oper = operators()
blend_name = "add"
a = input("Some input")
b = input("Some other input")
result = oper.calculate(blend_name, a, b)
print(result)
You can create a dictionary that maps the function names to their function objects and use that to call them. For example:
functions = {"add": add, "sub": sub} # and so on
func = functions[blend_name]
result = func(a, b)
Or, a little more compact, but perhaps less readable:
result = functions[blend_name](a, b)
You could use the globals() dictionary for the module.
result = globals()[blend_name](a, b)
It would be prudent to add some validation for the values of blend_name

How to pass a list of inputs into a constructor in Python?

Let's say I have a Python constructor
def foo(a, b, c):
__def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
and I have a list of inputs
bar = [a, b, c]
Is there a way I can call the constructor with just a list of inputs? Eg,
foobar = foo(bar)
Or would I need to make an entire wrapper function, such as:
def fooWrapper(inputList):
a = inputList[0]
b = inputList[1]
c = inputList[2]
return foo(a, b, c)
Assuming I cannot change neither the constructor nor the way I receive the inputs (as a list), is there a more simple way to do this than creating a wrapper?
Thank you.
This should do the work for the wrapper function:
def f(a, b, c):
return sum([a, b, c])
bar = [3, 2, 1]
total = f(*bar)
print(total)
Outputs 6.
Since a constructor can not return a value, yes you need a wrapper.

Python -- optional arguments for a function

Say I want to build a function that either adds two numbers a and b , or subtracts them and adds a third number c and subtracts the fourth number d. I intend to specify which of the two operations is to be performed by an argument sum; if this is True, the first operation is performed, if False, then the second operations is performed. I would write this as:
def f(a, b, c, d, sum=True):
if sum: return a+b
else: return a-b+c-d
For example, f(1,2,3,4) returns 3, while f(1,2,3,4,sum=False) returns -2, as expected. Clearly, though, c and d only need to be defined when sum=False. How do I do this? I've tried setting c and d as *args, but I keep getting errors of the type "unsupported operand" or "positional argument follows keyword argument".
Use a default value of None for c and d:
def f(a, b, c=None, d=None, sum=True):
if sum:
return a+b
else:
return a-b+c-d
This also allows you to add error-checking logic to your function - check whether c and d are present when sum is False:
def f(a, b, c=None, d=None, sum=True):
if sum:
return a+b
else:
if None in (c, d):
raise TypeError('f requires c and d args with parameter sum=False')
return a-b+c-d
Others have given the way you can do it, but at a more fundamental level I'd ask why this is even the same method? Seems to me you have two different methods here, f_sum and f (or whatever), one takes two parameters and the other 4.
Or if it's a more complex operation and c and d are just additional parameters / attributes, you could default them to whatever the null value is e.g. for addition just default them to 0:
def f(a, b, c=0, d=0)
a+b-0+0 won't do anything so if these parameters are not provided the result will be identical to a+b without even needing a conditional or magical flag.
sorry missed that the second case was a - b and misread it as a +
This solves your problem:
def f(a, b, c=0, d=0, sum=True):
if sum: return a+b
else: return a-b+c-d
The answer to your question is:
def f(a, b, c=None, d=None, sum=True):
if sum: return a + b
else: return a - b + c - d
However, you could further simplify it to this:
def f(a, b, c=0, d=0):
return a - b + c - d
As the values of c and d depend on whether sum is true or false.

How to return (a varying number of) objects with their original name in a function in Python

I'm very new to Python. I'm looking to return a varying number of objects (will eventually be lists or pandas), ideally with their original name.
So far I'm looking at something like this:
def function(*Args):
Args = list(Args)
for i in range(len(Args)):
Args[i] += 1
print Args[i]
return *all variables with original name, in this case a, b, c, d *
a=1
b=2
c=3
d=4
a, b, c, d = function(a, b, c, d)
Any help, ideas or comments would be very appreciated. Thanks.
Are you just looking to return the tuple?
def function(*Args):
Args = list(Args)
for i in range(len(Args)):
Args[i] += 1
print Args[i]
return Args
a, b, c, d = function(a, b, c, d)
In the meantime I tried it as #Xavier C. suggested and it seems to work. the lists/input arguments i would name after the industry and would therefore like to preseve. Is there any way to achieve that?
def BBGLiveRequest(*args):
data = []
for i in range(len(args)):
print args[i]
result = BLPTS(args[i], ['PX_Last'])
result.get()
print result.output
data.append(result.output)
return data

Categories