Apply function taking one argument to a value in Python - python

I don't really get how that works, why is 10 not an variable of the function? I never saw a case where you would apply a function to an item outside of that function. I don't want the answer to the problem, just want to understand it.
Thanks guys
Write a function called general_poly, that meets the specifications below.
For example, general_poly([1, 2, 3, 4])(10) should evaluate to 1234 because 1∗103+2∗102+3∗101+4∗100
So in the example the function only takes one argument with general_poly([1, 2, 3, 4]) and it returns a function that you can apply to a value, in this case x = 10 with general_poly([1, 2, 3, 4])(10).

It's asking you for general_poly to return a function, e.g.:
def general_poly(L):
def inner(x):
return sum(x+e for e in L)
return inner
general_poly([1,2,3,4])(10)
# 11+12+13+14 = 50
This should give you enough to be able to work through your homework.

def general_poly (L):
""" L, a list of numbers (n0, n1, n2, ... nk)
Returns a function, which when applied to a value x, returns the value
n0 * x^k + n1 * x^(k-1) + ... nk * x^0 """
def inner(x):
L.reverse()
return sum(e*x**L.index(e) for e in L)
return inner

Related

How do I manipulate functions to take new arguments?

I was wondering how I could manipulate a function to take a new argument in Python without modifying original formula.
For example, how would I take square function and make another function like multiply square using square function as a model:
Original Function:
def square(x):
result = (x*x)
return(result)
New Function, takes a new argument "y":
def multSquare(x,y):
result = y*square(x)
return(result)
I tried using decorators but I can't seem to have it working
def addArg(tarFun):
def wrapArg(y, *args, **kwargs):
result=tarFun(*args, **kwargs) * y
return result
return wrapArg
def square(x):
result = (x*x)
return(result)
multSquare = addArg(square)
print(square(2)) # This should be 4
print(multSquare(2,3)) # This should be 12
This doesn't work because I don't how to inject y.
In the end, I want to make a function that takes all the arguments of the original function plus one more argument.
Thanks everybody!
If you pay attention to the order of your arguments, what's happening is that you are squaring 3 and multiplying it by 2. This is because your function wrapArg uses the first argument (2) as the number you are multiplying with and the second (3) as the number you are squaring.
multSquare(3, 2) will give the result you want.
In additional to what busybear said you could just swap the parameters around
def addArg(fun):
def wrapArg(x, y):
result = fun(x) * y
return result
return wrapArg
def square(x):
result = (x * x)
return(result)
multSquare = addArg(square)
print(square(2)) # This should be 4
print(multSquare(2, 3)) # This should be 12
or additionally just use optional arguments
def square(x, y = None):
sq = x*x
if y:
sq *= y
return sq

Function that returns a function that returns a function

I've been given this function. It returns the function pair that it also returns the function f I think. That is the part that tricks me, I don't know what f(a, b) is and how to use it.
def cons(a, b):
def pair(f):
return f(a, b)
return pair
To help you understand what is going on, consider the following example:
def cons(a, b):
def pair(f):
return f(a, b)
return pair
def my_func(a, b):
return a + b
# cons returns a function that takes a function arg and calls it with args (a, b),
# in this case (1, 3). Here a, b are considered "closured" variables.
apply_func = cons(1, 3)
print apply_func(my_func) # prints 4
Lets analyse this from inside out:
def cons(a, b):
def pair(f):
return f(a, b)
return pair
The innermost level is return f(a, b) - that obviously calls function f with arguments (a, b) and returns whatever the result of that is.
The next level is pair:
def pair(f):
return f(a, b)
Function pair takes a function as an argument, calls that function with two arguments (a, b) and returns the result. For example:
def plus(x, y):
return x + y
a = 7
b = 8
pair(plus) # returns 15
The outermost level is cons - it constructs function pair which has arbitrary a and b and returns that version of pair. E.g.
pair_2_3 = cons(2,3)
pair_2_3(plus) # returns 5, because it calls plus(2, 3)
. . . I don't know what f(a, b) is and how to use it.
f(a, b) is simply a function call. All the code you provided does is define a function that returns a function. The function returned from the first function, itself returns a function. I assume the way it would be used is perhaps something like:
>>> cons(1, 2)(lambda x, y: x + y)
3
>>>
The above code would be equivalent to:
>>> pair_func = cons(1, 2) # return the `pair` function defined in `cons`
>>> f = lambda x, y: x + y
>>> pair_func(f) # apply the `f` function to the arguments passed into `cons`.
3
>>>
It might also help to note that the pair function defined in this case, is what's know as a closure. Essentially, a closure is a function which has access to local variables from an enclosing function's scope, after the function has finished execution. In your specific case, cons is the enclosing function, pair is the closure, and a and b are the variables the closure is accessing.
Well if you could share the complete question then we might be able to help you better. Meanwhile what I can tell you here is that in the return of pair(f) the program is calling a function f which takes two arguments a and b. This function f(a,b) is called and then its value will be returned to pair(f).
But the point to note here is that in pair function we already have a local variable f, so when we will try to call the function f(a,b) it will give us UnboundedLocalVariable error. Therefore, we will need to change the name of this function from f to something else.

Double sum in Python

I am now programming on BFGS algorithm, where I need to create a function with a doulbe sum. I need to return a FUNCTION but not a number, so something like sum+= is not acceptable.
def func(X,W):
return a function of double sum of X, W
A illustrative example:
X = np.array([[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]])
W = np.array([[1,1,1,1],[2,2,2,2],[3,3,3,3]])
I want to get a function that, for each instance X[i] in X, and for each W[j] in W, return a function of the sum of numpy.dot(X[i],W[j]). For example, X[1] dot W[2] shoulde be 2*3+2*3+2*3+2*3
----------This contend is edited by me:-------------
When I saw the answers provided below, I think my question is not clear enough. Actually, I want to get a function:
Func = X[0]W[0]+X[0]W[1]+X[0]W[2]+ X[1]W[0]+X[1]W[1]+X[1]W[2]+
X[2]W[0]+X[2]W[1]+X[2]W[2]+ X[3]W[0]+X[3]W[1]+X[3]W[2] +
X[4]W[0]+X[4]W[1]+X[4]W[2]
-------------------end the edited content--------------
If I only got one dimension of W, the problem is easy by using numpy.sum(X,W).
However, how can I return a function of two sums with Python?
If you want to return the function f(i,j) -> X[i].W[j] :
def func(X,W):
def f(i,j): return np.dot(X[i],W[j])
return f
will work.
EDIT:
The VALUE you name Func in your edit is computed by sum([np.dot(x,w) for x in X for w in W]) or, more efficient, np.einsum('ij,kj->',X,W) .
if you want to return the FUNCTION that return Func, you can do it like that :
def func(X,W):
Func=np.einsum('ij,kj->',X,W)
return lambda : Func
Then f=func(X,W); print(f()) will print 360, the value named Func in your example.
If I got your question right, this should do exactly what you want (python-2.7):
import numpy as np
def sample_main():
X = np.array([[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]])
W = np.array([[1,1,1,1],[2,2,2,2],[3,3,3,3]])
f = lambda i, j : reduce (lambda a, b: a+b, map(lambda x, w: x*w, X[i], W[j]), 0)
return f
if __name__ == '__main__':
f = sample_main()
print (f(0, 0))
Just replace the sample_main function with your function that takes X and W.
Actually, I want to implement L_BFGS algorithm in my Python code. Inspired by the two answers provided by #B.M. and #siebenschlaefer, I figure out how to implement in my code:
func = np.sum(np.sum(log_p_y_xz(Y[i][t], Z[i], sigma_eta_ti(X[i],w[t],gamma[t]))+log_p_z_x(alpha, beta, X[i]) for t in range(3)) for i in range (5))
Please do not mind the details of the formula, what I want to say is that, I use two sum here and just using i in rage (5) and t in range (3) to tell the code do the sums.
Thanks again for the answers provided by #B.M. and #siebenschlaefer!!

Want to refer to variable in the outer function's scope from an inner function being returned

So I'm making a simple program that gets 2 functions(a and k) and one integer value(b), then it gets the formal parameter in the two functions(a and k) which is "x" and applies a condition x < b then based on the condition makes a function call, either a or b. But when I run the program it gives an error that x is not defined in the global frame. I want it to get "x" from the formal parameter assigned to the functions a and b and then get the condition based on that.
Here's my code
def square(x):
return x * x
def increment(x):
return x + 1
def piecewise(a, k, b):
if x<b:
return a
else:
return k
mak = piecewise(increment,square ,3 )
print(mak(1))
I guess you want to do something like this:
def piecewise(a, k, b):
def f(x):
if x < b:
return a(x)
else:
return k(x)
return f
However, I am not sure if it is a good practice. So, I leave my answer here to see the comments and learn if there is any problem with it.

calculating current value based on previous value

i would like to perform a calculation using python, where the current value (i) of the equation is based on the previous value of the equation (i-1), which is really easy to do in a spreadsheet but i would rather learn to code it
i have noticed that there is loads of information on finding the previous value from a list, but i don't have a list i need to create it! my equation is shown below.
h=(2*b)-h[i-1]
can anyone give me tell me a method to do this ?
i tried this sort of thing, but that will not work as when i try to do the equation i'm calling a value i haven't created yet, if i set h=0 then i get an error that i am out of index range
i = 1
for i in range(1, len(b)):
h=[]
h=(2*b)-h[i-1]
x+=1
h = [b[0]]
for val in b[1:]:
h.append(2 * val - h[-1]) # As you add to h, you keep up with its tail
for large b list (brr, one-letter identifier), to avoid creating large slice
from itertools import islice # For big list it will keep code less wasteful
for val in islice(b, 1, None):
....
As pointed out by #pad, you simply need to handle the base case of receiving the first sample.
However, your equation makes no use of i other than to retrieve the previous result. It's looking more like a running filter than something which needs to maintain a list of past values (with an array which might never stop growing).
If that is the case, and you only ever want the most recent value,then you might want to go with a generator instead.
def gen():
def eqn(b):
eqn.h = 2*b - eqn.h
return eqn.h
eqn.h = 0
return eqn
And then use thus
>>> f = gen()
>>> f(2)
4
>>> f(3)
2
>>> f(2)
0
>>>
The same effect could be acheived with a true generator using yield and send.
First of, do you need all the intermediate values? That is, do you want a list h from 0 to i? Or do you just want h[i]?
If you just need the i-th value you could us recursion:
def get_h(i):
if i>0:
return (2*b) - get_h(i-1)
else:
return h_0
But be aware that this will not work for large i, as it will exceed the maximum recursion depth. (Thanks for pointing this out kdopen) In that case a simple for-loop or a generator is better.
Even better is to use a (mathematically) closed form of the equation (for your example that is possible, it might not be in other cases):
def get_h(i):
if i%2 == 0:
return h_0
else:
return (2*b)-h_0
In both cases h_0 is the initial value that you start out with.
h = []
for i in range(len(b)):
if i>0:
h.append(2*b - h[i-1])
else:
# handle i=0 case here
You are successively applying a function (equation) to the result of a previous application of that function - the process needs a seed to start it. Your result looks like this [seed, f(seed), f(f(seed)), f(f(f(seed)), ...]. This concept is function composition. You can create a generalized function that will do this for any sequence of functions, in Python functions are first class objects and can be passed around just like any other object. If you need to preserve the intermediate results use a generator.
def composition(functions, x):
""" yields f(x), f(f(x)), f(f(f(x)) ....
for each f in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
yield x
Your specs require a seed and a constant,
seed = 0
b = 10
The equation/function,
def f(x, b = b):
return 2*b - x
f is applied b times.
functions = [f]*b
Usage
print list(composition(functions, seed))
If the intermediate results are not needed composition can be redefined as
def composition(functions, x):
""" Returns f(x), g(f(x)), h(g(f(x)) ....
for each function in functions
functions is an iterable of callables taking one argument
"""
for f in functions:
x = f(x)
return x
print composition(functions, seed)
Or more generally, with no limitations on call signature:
def compose(funcs):
'''Return a callable composed of successive application of functions
funcs is an iterable producing callables
for [f, g, h] returns f(g(h(*args, **kwargs)))
'''
def outer(f, g):
def inner(*args, **kwargs):
return f(g(*args, **kwargs))
return inner
return reduce(outer, funcs)
def plus2(x):
return x + 2
def times2(x):
return x * 2
def mod16(x):
return x % 16
funcs = (mod16, plus2, times2)
eq = compose(funcs) # mod16(plus2(times2(x)))
print eq(15)
While the process definition appears to be recursive, I resisted the temptation so I could stay out of maximum recursion depth hades.
I got curious, searched SO for function composition and, of course, there are numerous relavent Q&A's.

Categories