How can I pass method as function parameter without 'lambda' keyword? - python

Can I somehow refer to a method without using the lambda keyword?
Say we have following example code:
class AbstractDummy:
def size(self):
raise NotImplementedError
class Dummy1(AbstractDummy):
def size(self):
return 10
class Dummy2(AbstractDummy):
def size(self):
return 20
If I have my example objects:
dummies1 = [Dummy1(), Dummy1(), Dummy1()]
dummies2 = [Dummy2(), Dummy2()]
Then if I want to map them, and I can do that with extracted function parameter to save me some characters:
f = lambda x : x.size()
map(f, dummies1)
map(f, dummies2)
Question here: can I somehow avoid this temporary f and/or lambda keyword?
To make a small comparison, in Java it would be possible to refer to AbstractDummy::size and so the invocation would look a bit like print(map(AbstractDummy::size, dummies1).

The operator module provides methodcaller for this.
from operator import methodcaller
f = methodcaller('size')
results1 = [f(x) for x in dummies1]
results2 = [f(x) for x in dummies2]
though [x.size() for x in ...] is simpler, as in C_Z_'s answer. methodcaller is useful for when you need a function as a function argument, for example
# Sort some_list_of_objects on return value of each object's `a` method.
sorted_list = sorted(some_list_of_objects, key=methodcaller('a'))

In this case you would probably want to use a list comprehension
[x.size() for x in dummies1]
[x.size() for x in dummies2]

Related

How to create a function that applies a function to the inputs of another function in Python?

I'm looking for a nice functional way to do the following:
def add(x, y):
return x + y
def neg(x):
return -x
def c(x, y):
# Apply neg to inputs for add
_x = neg(x)
_y = neg(y)
return add(_x, _y)
neg_sum = c(2, 2) # -4
It seems related to currying, but all of the examples I can find use functions that only have one input variable. I would like something that looks like this:
def add(x, y):
return x + y
def neg(x):
return -x
c = apply(neg, add)
neg_sum = c(2, 2) # -4
This is a fairly direct way to do it:
def add(x, y):
return x + y
def neg(x):
return -x
def apply(g, f):
# h is a function that returns
# f(g(arg1), g(arg2), ...)
def h(*args):
return f(*map(g, args))
return h
# or this:
# def apply(g, f):
# return lambda *args: f(*map(g, args))
c = apply(neg, add)
neg_sum = c(2, 2) # -4
Note that when you use *myvar as an argument in a function definition, myvar becomes a list of all non-keyword arguments that are received. And if you call a function with *expression as an argument, then all the items in expression are unpacked and sent as separate arguments to the function. I use these two behaviors to make h accept an unknown list of arguments, then apply function g to each one (with map), then pass all of them as arguments to f.
A different approach, depending on how extensible you need this to be, is to create an object which implements your operator methods, which each return the same object, allowing you to chain operators together in arbitrary orders.
If you can cope with it always returning a list, you might be able to make it work.
class mathifier:
def __init__(self,values):
self.values = values
def neg(self):
self.values = [-value for value in self.values]
return self
def add(self):
self.values = [sum(self.values)]
return self
print (mathifier([2,3]).neg().add().values)
And you can still get your named function for any set of chained functions:
neg_add = lambda x : mathifier(x).neg().add()
print(neg_add([2,3]).values)
From Matthias Fripp's answer, I asked myself : I'd like to compose add and neg both ways : add_neg(*args) and neg_add(*args). This requires hacking Matthias suggestion a bit. The idea is to get some hint on the arity (number of args) of the functions to compose. This information is obtained with a bit of introspection, thanks to inspect module. With this in mind, we adapt the way args are passed through the chain of funcs. The main assumption here is that we deal with real functions, in the mathematical sense, i.e. functions returning ONE float, and taking at least one argument.
from functools import reduce
from inspect import getfullargspec
def arity_one(func):
spec = getfullargspec(func)
return len(spec[0])==1 and spec[1] is None
def add(*args):
return reduce(lambda x,y:x+y, args, 0)
def neg(x):
return -x
def compose(fun1,fun2):
def comp(*args):
if arity_one(fun2): return fun1(*(map( fun2, args)))
else: return fun1(fun2(*args))
return comp
neg_add = compose(neg, add)
add_neg = compose(add, neg)
print(f"-2+(-3) = {add_neg(2, 3)}")
print(f"-(2+3) = {neg_add(2, 3)}")
The solution is still very adhoc...

How to take the logical and of a list of boolean functions in python

Say I have a list of functions li = [fun1, fun2, ..., funk] that take one argument and return a boolean. I'd like to compose them into a single function that returns the logical and of the return values of each of the fun's when evaluated at its argument. (in other words I'd like to have fun(x) = fun1(x) and fun2(x) and ... and funk(x).)
Is there an elegant way of doing this?
Use all to create the composite function
def func(x, lst):
#lst is the list of functions and x is used as an argument for functions
return all(fun(x) for fun in lst)
And then call it as
func(x,[fun1, fun2, fun3,...., funk])
If a lambda function is needed, you can do the following, however it is against PEP-8 guidelines
Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier.
func = lambda x:all(fun(x) for fun in lst)
And call it as
func(x)
all will do it
all(func(x) for func in li)

how to pass nested function as an argument

Lets say we have functions in python:
def _abs(iterable): #cause its normally for one element only
return [abs(i) for i in iterable]
def A(list, foo):
return foo(list)
list = [2,3,-5]
print( A(list,foo=sum) )
>> 0
while I may pass foo=sum to A, I am looking for an elegant way to pass something like foo=sum(_abs) to perform sum(_abs(list)).
The only way I see it now is to send a list of functions [sum, _abs] and apply them in order. Is there a better way?
Or, to compose more generally (i.e. with an arbitrary number of argument functions):
from functools import partial, reduce
def compose(*funcs):
return partial(reduce, lambda x, f: f(x), reversed(funcs))
(see the docs on partial and reduce - note you don't need to import reduce in Python 2.x)
Then:
>>> compose(sum, _abs)([2, 3, -5])
10
You could make an explicit compose function
>>> def compose(f, g):
... return lambda x: f(g(x))
...
Then use it
>>> A(list, compose(sum, _abs))
10
def compose(funcs, funcargs):
for func in reversed(funcs):
funcargs = func(funcargs)
return funcargs

Sequential function mapping in python

I have a bunch of functions in a list:
funcs = [f1, f2, f3, f4, f5]
and all of the functions take in return a single argument, eg.
f1 = lambda x: x*2
I'd like to map all these functions together
result = lambda x: f5(f4(f3(f2(f1(x)))))
or, iterating over funcs
def dispatch(x):
for f in funcs:
x = f(x)
return x
dispatch works fine, but I couldn't figure out a clean way to do this using iterools. Is it possible? Does this sequential function mapping idiom have a name?
There is no point in using itertools here; you are producing one output, and you could not apply this to an infinite iterable. You have to have a finite number of functions in the input iterable for this to work at all.
Use the reduce() function:
from functools import reduce
x = reduce(lambda res, func: func(res), funcs, x)
The functools.reduce() import helps the above work in both Python 2 and 3.
reduce(), together with map(), filter() and, yes, itertools, is an often used tool in functional programming.
Another (less efficient, alas) way of looking at Martijn's answer is to realize that you want to compose the list of functions.
# function composition: compose(f,g)(x) = f(g(x))
def compose(f, g):
return lambda x: f(g(x))
# Identity for function composition
# compose(f, identity)(x) = f(x)
identity = lambda x: x
# result(x) = f1(f2(...fn(x)...))
result = reduce(compose, funcs, identity)

Return function with function

I would like to do something like the following:
def getFunction(params):
f= lambda x:
do stuff with params and x
return f
I get invalid syntax on this. What is the Pythonic/correct way to do it?
This way I can call f(x) without having to call f(x,params) which is a little more messy IMO.
A lambda expression is a very limited way of creating a function, you can't have multiple lines/expressions (per the tutorial, "They are syntactically restricted to a single expression"). However, you can nest standard function definitions:
def getFunction(params):
def to_return(x):
# do stuff with params and x
return to_return
Functions are first-class objects in Python, so once defined you can pass to_return around exactly as you can with a function created using lambda, and either way they get access to the "closure" variables (see e.g. Why aren't python nested functions called closures?).
It looks like what you're actually trying to do is partial function application, for which functools provides a solution. For example, if you have a function multiply():
def multiply(a, b):
return a * b
... then you can create a double() function1 with one of the arguments pre-filled like this:
from functools import partial
double = partial(multiply, 2)
... which works as expected:
>>> double(7)
14
1 Technically a partial object, not a function, but it behaves in the same way.
You can't have a multiline lambda expression in Python, but you can return a lambda or a full function:
def get_function1(x):
f = lambda y: x + y
return f
def get_function2(x):
def f(y):
return x + y
return f

Categories