Imagine this situation:
def foo1(item1, item2, item3):
pass
def foo2(item4, item5):
pass
item_to_pass = "random item"
x = 3
I need to call one of the functions which takes x arguments. As parameters, I want to pass item_to_pass (or any other variable).
Basically, I know how to find out how many parameters does a function have using inspect module. But what I don't know is how to call a certain function with those arguments (let's say those arguments are all the same). Also note that I can not pass a list of items as an argument instead of multiple parameters, I need to have different amount of arguments and based on that call the function.
Do you have any idea, how could I solve this?
Is this what you are looking for:
import inspect
def foo1(item1, item2, item3):
print("foo1 called")
def foo2(item4, item5):
print("foo2 called")
def fooWrapper(*args):
# map functions to function's arguments
funcs = {fn: len(inspect.getfullargspec(fn).args) for fn in (foo1, foo2)}
# lookup all functions that take the same amount of arguments as given.
for fn, argLen in funcs.items():
if len(args) == argLen:
fn(*args)
break
item_to_pass = "random item"
x = 3
foo1_Argument = "foo"
fooWrapper(item_to_pass, x)
fooWrapper(item_to_pass, x, foo1_Argument)
Out:
foo2 called
foo1 called
Related
Let's say I have a function given below:
def splitter(*params):
rep, msg = params
if rep:
for i in range(rep):
print(i)
else:
print('-----------------------------------')
splitter(2,'Let the Game Begin!! 🏏')
Now, in the above case it will pass since I'm giving the arguments, but what I want is, that suppose I don't want to give the arguments when calling the function, then how can I handle it? Since *args cannot have a default value.
Define the function with named arguments having default values:
def splitter(rep=None, msg=None):
if rep is not None:
...
I only just started learning Python and found out that I can pass a function as the parameter of another function. Now if I call foo(bar()) it will not pass as a function pointer but the return value of the used function. Calling foo(bar) will pass the function, but this way I am not able to pass any additional arguments. What if I want to pass a function pointer that calls bar(42)?
I want the ability to repeat a function regardless of what arguments I have passed to it.
def repeat(function, times):
for calls in range(times):
function()
def foo(s):
print s
repeat(foo("test"), 4)
In this case the function foo("test") is supposed to be called 4 times in a row.
Is there a way to accomplish this without having to pass "test" to repeat instead of foo?
You can either use a lambda:
repeat(lambda: bar(42))
Or functools.partial:
from functools import partial
repeat(partial(bar, 42))
Or pass the arguments separately:
def repeat(times, f, *args):
for _ in range(times):
f(*args)
This final style is quite common in the standard library and major Python tools. *args denotes a variable number of arguments, so you can use this function as
repeat(4, foo, "test")
or
def inquisition(weapon1, weapon2, weapon3):
print("Our weapons are {}, {} and {}".format(weapon1, weapon2, weapon3))
repeat(10, inquisition, "surprise", "fear", "ruthless efficiency")
Note that I put the number of repetitions up front for convenience. It can't be the last argument if you want to use the *args construct.
(For completeness, you could add keyword arguments as well with **kwargs.)
You will need to pass the parameters for foo, to the repeat function:
#! /usr/bin/python3.2
def repeat (function, params, times):
for calls in range (times):
function (*params)
def foo (a, b):
print ('{} are {}'.format (a, b) )
repeat (foo, ['roses', 'red'], 4)
repeat (foo, ['violets', 'blue'], 4)
While many of the answers here are good, this one might be helpful because it doesn't introduce any unnecessary repetition and the reason for callbacks in the first place is often to synchronize with other work outside of the main UI thread.
Enjoy!
import time, threading
def callMethodWithParamsAfterDelay(method=None, params=[], seconds=0.0):
return threading.Timer(seconds, method, params).start()
def cancelDelayedCall(timer):
timer.cancel()
# Example
def foo (a, b):
print ('{} are {}'.format (a, b) )
callMethodWithParametersAfterDelay(foo, ['roses', 'red'], 0)
I have a class. This class has a list of functions that are to be evaluated by a different program.
class SomeClass(object):
def __init__(self, context):
self.functions_to_evaluate = []
There is a function that adds functions to an instance of SomeClass, via something like:
new_function = check_number(5)
SomeClassInstance.functions_to_evaluate.append(new_function)
Where check_number is a function that will check if number is greater than 10, let's say.
If I take SomeClassInstance.functions_to_evaluate and print it, I get a bunch of python objects, like so:
<some_library.check_number object at 0x07B35B90>
I am wondering if it is possible for me to extract the input given to check_number, so something like:
SomeClassInstance.functions_to_evaluate[0].python_feature() that will return "5" or whatever the input to check_number was to me.
You can use the standard library functools.partial, which creates a new partially applied function *.
>>> from functools import partial
>>> def check_number(input):
... return input > 10
>>> fn = partial(check_number, 5)
>>> fn.args # this attribute gives you back the bound arguments, as a tuple.
(5,)
>>> fn() # calls the function with the bound arguments.
False
*: actually the partial object is not a function instance, but it is a callable, and from a duck-type perspective it's a function.
If new_function = check_number(5) is a closure, then you can extract this value using __closure__[0].cell_contents:
Example:
def foo(x):
def inn(y):
return x
return inn
s = foo(5)
print(s.__closure__[0].cell_contents)
Output:
5
I understand your confusion, but:
new_function = check_number(5)
Is calling the function, and the new_function variable gets assigned the return value of the function.
If you have this check_number function:
def check_number(input):
return input > 10
Then it will return False, and new_function will be False. Never <some_library.check_number object at 0x07B35B90>.
If you're getting <some_library.check_number object at 0x07B35B90> then your check_number() function is returning something else.
There are probably several ways to skin this cat. But I'd observe first and foremost that you're not adding python function objects to the functions_to_evaluate list, you're adding the evaluations of functions.
You could simply add a tuple of function, args to the list:
SomeClassInstace.functions_to_evaluate.append((check_number, 5))
And then you can:
for f, args in SomeClassInstance.functions_to_evaluate:
print(args)
I only just started learning Python and found out that I can pass a function as the parameter of another function. Now if I call foo(bar()) it will not pass as a function pointer but the return value of the used function. Calling foo(bar) will pass the function, but this way I am not able to pass any additional arguments. What if I want to pass a function pointer that calls bar(42)?
I want the ability to repeat a function regardless of what arguments I have passed to it.
def repeat(function, times):
for calls in range(times):
function()
def foo(s):
print s
repeat(foo("test"), 4)
In this case the function foo("test") is supposed to be called 4 times in a row.
Is there a way to accomplish this without having to pass "test" to repeat instead of foo?
You can either use a lambda:
repeat(lambda: bar(42))
Or functools.partial:
from functools import partial
repeat(partial(bar, 42))
Or pass the arguments separately:
def repeat(times, f, *args):
for _ in range(times):
f(*args)
This final style is quite common in the standard library and major Python tools. *args denotes a variable number of arguments, so you can use this function as
repeat(4, foo, "test")
or
def inquisition(weapon1, weapon2, weapon3):
print("Our weapons are {}, {} and {}".format(weapon1, weapon2, weapon3))
repeat(10, inquisition, "surprise", "fear", "ruthless efficiency")
Note that I put the number of repetitions up front for convenience. It can't be the last argument if you want to use the *args construct.
(For completeness, you could add keyword arguments as well with **kwargs.)
You will need to pass the parameters for foo, to the repeat function:
#! /usr/bin/python3.2
def repeat (function, params, times):
for calls in range (times):
function (*params)
def foo (a, b):
print ('{} are {}'.format (a, b) )
repeat (foo, ['roses', 'red'], 4)
repeat (foo, ['violets', 'blue'], 4)
While many of the answers here are good, this one might be helpful because it doesn't introduce any unnecessary repetition and the reason for callbacks in the first place is often to synchronize with other work outside of the main UI thread.
Enjoy!
import time, threading
def callMethodWithParamsAfterDelay(method=None, params=[], seconds=0.0):
return threading.Timer(seconds, method, params).start()
def cancelDelayedCall(timer):
timer.cancel()
# Example
def foo (a, b):
print ('{} are {}'.format (a, b) )
callMethodWithParametersAfterDelay(foo, ['roses', 'red'], 0)
I've been playing around in depth with attempting to write my own version of a memoizing decorator before I go looking at other people's code. It's more of an exercise in fun, honestly. However, in the course of playing around I've found I can't do something I want with decorators.
def addValue( func, val ):
def add( x ):
return func( x ) + val
return add
#addValue( val=4 )
def computeSomething( x ):
#function gets defined
If I want to do that I have to do this:
def addTwo( func ):
return addValue( func, 2 )
#addTwo
def computeSomething( x ):
#function gets defined
Why can't I use keyword arguments with decorators in this manner? What am I doing wrong and can you show me how I should be doing it?
You need to define a function that returns a decorator:
def addValue(val):
def decorator(func):
def add(x):
return func(x) + val
return add
return decorator
When you write #addTwo, the value of addTwo is directly used as a decorator. However, when you write #addValue(4), first addValue(4) is evaluated by calling the addValue function. Then the result is used as a decorator.
You want to partially apply the function addValue - give the val argument, but not func. There are generally two ways to do this:
The first one is called currying and used in interjay's answer: instead of a function with two arguments, f(a,b) -> res, you write a function of the first arg that returns another function that takes the 2nd arg g(a) -> (h(b) -> res)
The other way is a functools.partial object. It uses inspection on the function to figure out what arguments a function needs to run (func and val in your case ). You can add extra arguments when creating a partial and once you call the partial, it uses all the extra arguments given.
from functools import partial
#partial(addValue, val=2 ) # you can call this addTwo
def computeSomething( x ):
return x
Partials are usually a much simpler solution for this partial application problem, especially with more than one argument.
Decorators with any kinds of arguments -- named/keyword ones, unnamed/positional ones, or some of each -- essentially, ones you call on the #name line rather than just mention there -- need a double level of nesting (while the decorators you just mention have a single level of nesting). That goes even for argument-less ones if you want to call them in the # line -- here's the simplest, do-nothing, double-nested decorator:
def double():
def middling():
def inner(f):
return f
return inner
return middling
You'd use this as
#double()
def whatever ...
note the parentheses (empty in this case since there are no arguments needed nor wanted): they mean you're calling double, which returns middling, which decorates whatever.
Once you've seen the difference between "calling" and "just mentioning", adding (e.g. optional) named args is not hard:
def doublet(foo=23):
def middling():
def inner(f):
return f
return inner
return middling
usable either as:
#doublet()
def whatever ...
or as:
#doublet(foo=45)
def whatever ...
or equivalently as:
#doublet(45)
def whatever ...