preserving order of function implementation - python

So I have a numeric value and on those two functions can be applied.
Lets say I have a number 8.
I want to take its square and then its log or first the log and then its square.
So my function looks something like this
def transform(value, transformation_list):
# value is int, transformation_list = ["log",square"] or ["square","log"]
# square function and log function
return transformed value
Now if the first argument of the transformation list is "square" and the second is "log",
then it should first execute square and then log
But if the first function in that list is "log" and second " square" then it should implement first log and then square.
I dont want if : else kinda thing as it will get ugly as i add more transformations
How should I design this.

Something like the following should work:
import math
func_dict = {'square': lambda x: x**2,
'cube': lambda x: x**3,
'log': math.log}
def transform(value, transformation_list):
for func_name in transformation_list:
value = func_dict[func_name](value)
return value
For example:
>>> transform(math.e, ['cube', 'log', 'square'])
9.0

Using this recipe for function composition (or alternatively, using the functional module), you can compose an arbitrary list of functions - no need to pass the names as strings, simply pass the functions:
class compose:
def __init__(self, f, g, *args, **kwargs):
self.f = f
self.g = g
self.pending = args[:]
self.kwargs = kwargs.copy()
def __call__(self, *args, **kwargs):
return self.f(self.g(*args, **kwargs), *self.pending, **self.kwargs)
def transform(value, transformation_list, inverted=False):
lst = transformation_list if inverted else reversed(transformation_list)
return reduce(compose, lst)(value)
Now you can call transform like this:
from math import *
value = 2
transformation_list = [sin, sqrt, log]
transform(value, transformation_list)
> -0.047541518047580299
And the above will be equivalent to log(sqrt(sin(2))). If you need to invert the order of function application, for example sin(sqrt(log(2))), then do this:
transform(value, transformation_list, inverted=True)
> 0.73965300649866683
Also, you can define functions in-line. For instance, F.J's example would look like this using my implementation:
transform(e, [lambda x:x**3, log, lambda x:x**2])
> 9.0

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

Is it possible to change parameter value in partial?

I want to find a clear and efficient way to be able to change parameter value set for functools.partial.
Let's see a simple example:
from functools import partial
def fn(a,b,c,d,e):
print(a,b,c,d,e)
fn12 = partial(fn, 1,2)
Later, I want to have something like:
fn12 [0] = 7
to replace the value on specific place without create a new partial, because it's pretty heavy code there.
Addition: i ask about general possibility to change partial value.
The naive example would be like :
def printme( a,b,c,d,e):
print(a,b,c,d,e)
class my_partial:
def __init__(self, fn, *args):
self.__func__ = fn
self. args = list(args)
def __call__(self, *next_args):
call = self. args + list(next_args)
return self. __func__(* (call) )
fn12 = my_partial(printme,1,2)
fn12(3,4,5)
fn12.args[1] = 7
fn12(3,4,5)
I need that for example for widgets, where action function is defined like :
rb.config(command = partial(...))
but then I'd like to change some parameters given in partial. I could do a new partial again but that looks kinda messy.
If it is permissible to look into the implementation of partial, then using __reduce__ and __setstate__ you can replace the args wholesale:
from functools import partial
def fn(a,b,c,d,e):
print(a,b,c,d,e)
fn12 = partial(fn, 1,2)
def replace_args(part, new_args):
_,_, f = part.__reduce__()
f, _, k, n = f
part.__setstate__( (f, new_args, k, n) )
fn12('c','d','e')
replace_args(fn12, (7,2))
fn12('c','d','e')
Output:
1 2 c d e
7 2 c d e
You can update partial parameters. For example if you have a function like this:
def f(a, b):
return a*b
func = partial(f, b=2)
func(1) # result: 1*2=2
Now, you can update partial parameter b like this:
func(1, b=7) # result: 1*7=7

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

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

Creating a new function as return in python function?

I was wondering if it is possible in python to do the following:
def func1(a,b):
return func2(c,d)
What I mean is that suppose I do something with a,b which leads to some coefficients that can define a new function, I want to create this function if the operations with a,b is indeed possible and be able to access this outside of func1.
An example would be a simple fourier series, F(x), of a given function f:
def fourier_series(f,N):
...... math here......
return F(x)
What I mean by this is I want to creat and store this new function for later use, maybe I want to derivate it, or integrate or plot or whatever I want to do, I do not want to send the point(s) x for evaluation in fourier_series (or func1(..)), I simply say that fourier_series creates a new function that takes a variable x, this function can be called later outside like y = F(3)... if I made myself clear enough?
You should be able to do this by defining a new function inline:
def fourier_series(f, N):
def F(x):
...
return F
You are not limited to the arguments you pass in to fourier_series:
def f(a):
def F(b):
return b + 5
return F
>>> fun = f(10)
>>> fun(3)
8
You could use a lambda (although I like the other solutions a bit more, I think :) ):
>>> def func2(c, d):
... return c, d
...
>>> def func1(a, b):
... c = a + 1
... d = b + 2
... return lambda: func2(c,d)
...
>>> result = func1(1, 2)
>>> print result
<function <lambda> at 0x7f3b80a3d848>
>>> print result()
(2, 4)
>>>
While I cannot give you an answer specific to what you plan to do. (Looks like math out of my league.)
I can tell you that Python does support first-class functions.
Python may return functions from functions, store functions in collections such as lists and generally treat them as you would any variable.
Cool things such as defining functions in other functions and returning functions are all possible.
>>> def func():
... def func2(x,y):
... return x*y
... return func2
>>> x = func()
>>> x(1,2)
2
Functions can be assigned to variables and stored in lists, they can be used as arguments for other functions and are as flexible as any other object.
If you define a function inside your outer function, you can use the parameters passed to the outer function in the definition of the inner function and return that inner function as the result of the outer function.
def outer_function(*args, **kwargs):
def some_function_based_on_args_and_kwargs(new_func_param, new_func_other_param):
# do stuff here
pass
return some_function_based_on_args_and_kwargs
I think what you want to do is:
def fourier_series(f,N):
#...... math here......
def F(x):
#... more math here ...
import math #blahblah, pseudo code
return math.pi #whatever you want to return from F
if f+N == 2: #pseudo, replace with condition where f,N turn out to be useful
return F
else:
return None
Outside, you can call this like:
F = fourier_series(a,b)
if F:
ans = F(x)
else:
print 'Fourier is not possible :('
The important thing from Python's point of view are:
Yes, you can write a function inside a function
Yes, you can return a function from a function. Just make sure to return it using return F (which returns the function object) as compared to return F(x) which calls the function and returns the value
I was scraping through some documentation and found this.
This is a Snippet Like your code:
def constant(a,b):
def pair(f):
return f(a,b)
return pair
a = constant(1,2) #If You Print variable-> a then it will display "<function constant.
#<locals>.pair at 0x02EC94B0>"
pair(lambda a, b: a) #This will return variable a.
Now, constant() function takes in both a and b and return a function called "Anonymous Function" which itself takes in f, and calls f with a and b.
This is called "closures". Closures is basically an Instance of a Function.
You can define functions inside functions and return these (I think these are technically closures):
def make_f(a, b):
def x(a, b):
return a+b
return x(a, b)

Categories