How to transfer function to a class? [duplicate] - python

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)

Related

Calling a function depending on number of parametres in Python

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

Redefining a function by supplying some of its arguments

let's suppose there is a function like below:
def func(arg1, args2):
# do sth using arg1 and arg2
In the runtime, I would like to keep use some value for args2 which we can't know when defining the func.
So what I would like to do is:
func_simpler = func(, args2=some_value_for_arg2)
func_simpler(some_value_for_arg1) # actual usage
Any idea on it? I know that there is a walk-around such as defining func better, but I seek for a solution more like func_simpler thing.
Thanks in advance!
You can use lambda in python
Original function
def func(arg1, arg2):
Then you get the value you want as default for arg2 and define simple_func
simple_func = lambda arg1 : func(arg1, arg2=new_default)
Now you can run simple_func
simple_func("abc") #"abc" = value for arg1
Hope I could help you
I was trying to solve this myself and I found a not-bad solution:
def func(a, b):
print(a, ": variable given everytime the model is used")
print(b, ": variable given when the model is defined")
enter code here
def model(b):
def model_deliver(a):
func(a, b)
return model_deliver
s = model(20)
s(12) #prints result as below
# 12 : variable given everytime the model is used
# 20 : variable given when the model is defined
Use functools.partial:
from functools import partial
def func(arg1, arg2):
print(f'got {arg1!r} and {arg2!r}')
simple_func = partial(func, arg2='something')
simple_func("value of arg1")
# got 'value of arg1' and 'something'
Using partial produces an object which has various advantages over using a wrapper function:
If the initial function and its arguments can be pickled, the partial object can be pickled as well.
The repr/str of a partial object shows the initial function information.
Repeated application of partial is efficient, as it flattens the wrappers.
The function and its partially applied arguments can be inspected.
Note that if you want to partially apply arguments of a method, use functools.partialmethod instead.

Is there syntactic sugar for a function that accepts a tuple?

Suppose I have a function that takes two arguments and performs some calculation on them:
def add(a, b):
return a + b
I want to call this function through a multiprocessing library which can only handle functions with a single argument. So, I change the function to take its argument as a single tuple instead:
def add2(ab):
a, b = ab
return a + b
However, this seems clunky to me. The variables essentially need to be defined (and documented) twice. If I were using a lambda function, I could just write the following and it will accept the tuple properly:
add3 = lambda (a, b): a + b
Unfortunately, my function is not trivial enough to implement as a lambda function. Is there any sort of syntactic sugar feature in python that would allow me to write a named function that accepts a tuple but treats each component of that tuple as a separate named argument? My attempts to search for solutions to this have mostly turned up references to the *args operator, but that does not apply here because I do not control the site where the function is called.
Here is an example of how the function is being called. Note that it is called via the multiprocessing library so I cannot pass more than one argument:
import multiprocessing
pool = multiprocessing.Pool(processes=4)
for result in pool.imap_unordered(add, [(1,2),(3,4)]):
print(result)
Answers for either python 2.7 or 3.x are welcome.
It's best not to alter the original function interface, making it less Pythonic.
In Python 2, write a wrapper function to use with multiprocessing.
def _add(args):
return add(*args)
In Python 3, just use Pool.starmap instead:
>>> def add(a, b):
... return a + b
...
>>> p = Pool()
>>> list(p.starmap(add, [(1, 2), ('hello', ' world')]))
[3, 'hello world']
If you are worried about repeating yourself (a and b appear too many times), simply give the incoming tuple a non-descriptive name.
def add(t):
a, b = t
return a + b
Or, in your specific case, you can avoid a and b altogether by indexing the tuple:
def add(addends):
return addends[0] + addends[1]
As an alternative, you could wrap your function so the source code has the familiar argument format, but the function in use has the tuple argument:
def tupleize(func):
def wrapper(tup):
return func(*tup)
return wrapper
#tupleize
def add(a, b):
return a+b
t = 1, 2
assert(add(t) == 3)
As I was writing this question, I found the way to do it in Python 2.7:
def add4((a, b)):
return a + b
However apparently this no longer works in Python 3, so additional answers regarding Python 3 would still be helpful.
You could use a decorator to extend the multiprocessing library function to take multiple arguments, do whatever you want to them, and then call it with a single argument.
For example, a simple decorator that takes any number of arguments, sums them together, then calls the original function with the total as a single argument:
import 3rdpartylib
def sum_args(func):
def inner(*args):
return func(sum(args))
return inner
# Replace imported function with decorated version
3rdpartylib = sum_args(3rdpartylib)
# Decorate your own libraries
#sum_args
def my_own_lib(number):
print("A:", number)
3rdpartylib(1,2,3,4)
my_own_lib(5,10,15)
The main advantage is that you can decorate/replace any number of methods with this same decorator function to achieve the same effect.

How to pass an argument to a function pointer parameter?

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)

Named keywords in decorators?

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 ...

Categories