I should probably start by saying that I am relatively new to python, but I have coded in java and Matlab before.
In python, the code
def func(f):
return f
g = func(cos)
print(g(0))
gives the result
>1.0
as g now is defined as the cosine function.
I want to write a function that calculates the derivative of any provided function using a finite difference approach. The function is defined as
def derivator(f, h = 1e-8):
and would like to achieve the follwing:
g = derivator(cos)
print(g(0)) # should be about 0
print(g(pi/2)) # should be about -1
At the moment my derivator function looks like this
def derivator(f, h = 1e-8):
return (f(x+h/2)-f(x-h/2))/h
which definitely is wrong, but I am not sure how I should fix it. Any thoughts?
Your current derivator() function (which should probably be called differentiator()) uses an undefined variable x and would return a single value, if x were defined--the value of f'(x). You want to return a function that takes an x value. You can define an inner function and return it:
def fprime(x):
return (f(x+h/2)-f(x-h/2))/h
return fprime
Because you don't use that function anywhere else, though, you can use lambda instead, which is also shorter:
return lambda x: (f(x+h/2)-f(x-h/2))/h
The only thing PEP 8 says about lambdas is that you should not assign the result of the lambda to a variable, then return it:
fprime = lambda x: (f(x+h/2)-f(x-h/2))/h # Don't do this!
return fprime
Make an inner function inside your derivator function and return it:
from math import cos, pi
def derivator(f, h = 1e-8):
def g(x):
return (f(x+h/2)-f(x-h/2))/h
return g
g = derivator(cos)
print(g(0)) # 0.0
print(g(pi/2)) # -0.999999993923
f and h will be part of the closure of the returned function.
You can also return a lambda expression to make it one line:
return lambda x: (f(x+h/2)-f(x-h/2))/h
Related
Can someone please explain to me how this nested lambdas + decorator work and what is the chronical
logic behind the output:
amp = lambda f: lambda g:lambda x:g(f(f(x)))
my_dec=amp(lambda x: "*"+x+"*")
#my_dec
def my_print(y):
print(y)
my_print("hello")
That's a tricky one:
amp is a function that takes another function f as parameter and return another funktion g taking a function x as parameter
you call amp with lambda x: "*"+x+"*", which is applied twice to the argument of the "innermost" function before passing it to the "middle" function; the result of that is your decorator my_dec
that decorator is then applied to the my_print function, making my_print the g parameter in the lambda g: ... returned by amp
finally, you pass "hello" to that decorated function, which is routed through f i.e. lambda x: "*"+x+"*" before being passed to g i.e. my_print
The whole thing becomes much clearer if you use proper def functions and longer parameter names (keeping the original g, f, and x for reference):
def amp(f_preproc):
def my_parameterized_dec(g_function):
def decorated_function(x_original_arg):
new_arg = f_preproc(f_preproc(x_original_arg))
return g_function(new_arg)
return decorated_function
return my_parameterized_dec
#amp(lambda x: "*"+x+"*")
def my_print(y):
print(y)
If I have a function that takes in a lambda reference as a parameter, and returns that reference so when it's called, it returns the value of that lambda function (boolean).
Is there a way to have it return the opposite boolean value?
def returns_diff(lambda_function):
return lambda_function
f = returns_diff(lambda x : x > 2)
f(0)
# I know I can do it this way but I want to do it inside the function.
# print(not(f(0)))
---> Should return True because it's supposed to return False since 0 is not bigger than two (return the opposite value of the lambda function)
I know I can just do: not(f(0)) when calling it, but I want to do it inside the function, not when I call it.
If you want to generate a function that returns the boolean opposite of a given function, you can do it like this:
def returns_diff(func):
return lambda x: not func(x)
f = returns_diff(lambda x: x>2)
f(0) # returns True
That's assuming the functions take one argument, as in your question. You can also make a version that works for functions with any number of positional or keyword arguments:
def returns_diff(func):
return lambda *args, **kwargs: not func(*args, **kwargs)
Can i use classes? Or it need to be just plain functions? With classes i would do
class diff:
def __init__(self,lambda_func):
self.lambda_func = lambda_func
def __call__(self,x):
return not(self.lambda_func(x))
f = diff(lambda x: x > 2)
f(0) #True
I am given a list of functions and asked to define plus(x,y) with add1 and repeated. plus is a function that takes in two numbers and returns the total. However, I cannot get any output with my definition. It just gives the name of the function. Any help is appreciated!
add1 = lambda x: x + 1
def compose(f, g):
return lambda x: f(g(x))
def repeated(f, n):
if n == 0:
return lambda x: x
else:
return compose(f, repeated(f, n - 1))
def plus(x, y):
return repeated(add1, y)
That is an interesting way to do addition. It works quite well, you just missed one thing. Repeated returns a function which will give the sum, not the sum itself. So you just have to call repeated(add1, y) on x like this
def plus(x, y):
return repeated(add1, y)(x)
The rest of the code works fine.
The detail is that plus returns a function and that's why you see the name of the function instead of a numeric value. I think that's why there is the x parameter in plus. Just change this line of code to
return repeated(add1, y)(x)
This will evaluate the return function of repeated with the value in x.
So using
plus(5, 1)
>> 6
I'm trying to write a function in Python for a polynomial p that is a linear combination of n basis functions phi_i. How can I define a function that is itself a sum of n other functions?
I know that this works:
phi1 = lambda x: x**2
phi2 = lambda x: x
p = lambda x: phi1(x) + phi2(x)
But if I try a loop like this:
p = lambda x: 0
for i in range(0,n):
p = lambda x: p(x)+phi[i](x)
where phi is a list of my basis functions, I create an infinite loop.
I checked Writing a function that is sum of functions, but unfortunately that's not in Python.
You can do this by passing a simple generator expression to sum:
def sigma(funcs, x):
return sum(f(x) for f in funcs)
phi = [lambda x: x**2, lambda x: x]
y = sigma(phi, x)
BTW, it's considered bad style to use lambda for named functions, it's supposed to be for anonymous functions.
If you want a function that doesn't need phi to be passed in each time you call it, there are a couple of ways to do that. The easiest way is to simply use phi in the function. Eg,
def sigma(x):
return sum(f(x) for f in phi)
However, that has a couple of downsides. It won't work if phi isn't in the scope where you call sigma; you can get around that by making phi global, but that may not be convenient, and it's best to avoid globals when they aren't necessary. The other downside is that it uses the current contents of phi, not the contents it had when sigma was defined, so if you modify the contents of phi those changes will be reflected in sigma, which may or may not be desirable.
Another option is to use a closure to create the function. Then we won't be affected by the scope issue: you can call the resulting summing function inside a scope where the original function list isn't visible. We can also create a copy of the function list, so it won't be affected by changes to the passed-in function list.
def make_adder(funcs):
# Copy the function list
funcs = funcs[:]
def sigma(x):
return sum(f(x) for f in funcs)
return sigma
phi = [lambda x: x**2, lambda x: x]
sigma = make_adder(phi)
y = sigma(x)
Yet another option is to use my original sigma and pass it and the phi functions to functools.partial, eg
from functools import partial
sig = partial(sigma, phi)
y = sig(x)
Straight answer to OP
Store your phis in a list:
phis = [
lambda x: x**2,
lambda x: x,
]
p = lambda x: sum(phi(x) for phi in phis)
Further considerations
If you want to achieve a polynomial, I would suggest something similar to this:
def poly(c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
poly function accepts a sequence as the only argument, where its elements need to be int or float. The first element is assigned as the coeficient of x^0, the second to x^1 and so on. So your example (p(x) = x + x^2) would end up being constructed like this: p = poly([0, 1, 1])
Another option is to accept any number of arguments where each of them needs to be a int or float instead of the first being a sequence. This would only require to add one * to the function declaration.
def poly(*c):
return lambda x: sum(f(x) for f in [lambda x, i=i: c[i]*x**i for i in range(len(c))])
To construct your example with this function you would not require the list: p = poly(0, 1, 1).
Any of those methods would create a polynomic function that can be called as you would expect: p(1) would return 2, p(2) would return 6 and so on.
Function explained
def poly(c):
# Create a list where we are gonna store the functions for every term in the polynomial
terms = []
# Create as many terms as the arguments length
for i in range(len(c)):
# Each term is the product of the nth coefficient from c and x to the power of n
terms.append(lambda x, n=i: c[n]*x**n)
# The second parameter n is needed because if we pass i directly
# inside the function algorithm, Python wouldn't check its value
# inmediately, but when it gets executed, and by then the loop will
# be finished and i would be constant for every term. This argument
# is not exposed to the polynomial function as the next lambda only
# has one argument, so there is no way to wrongly call this function
# We return a function that adds the result of every term
return lambda x: sum(f(x) for f in terms)
Lets say we have two defined function objects
add1 = lambda x: x+1
and
square = lambda x: x*x
now I want to have a function that calls and adds the result of these two functions.
What I thought would work is:
def addFuncs(f,g):
f+g
addFuncs(add1,square)(10)
Which I thought would give me an answer of 111 (10*10 + 10+1)
But that just gave me an error TypeError: unsupported operand type(s) for +: 'function' and 'function'
So I tried:
def addFunctions(f, g):
def getf():
return f
def getg():
return g
return getf() + getg()
But still to no avail...
However, if I do
def addFunctions(f, g):
return f
it pops out with 100, so it seems to evaluate the function on return, But I can't figure out how to get it to evaluate the functions first and then operate on them.
Any help would be greatly appreciated!
EDIT
Got it!
def addFunctions(f, g):
return lambda x: f(x) + g(x)
def addFuncs(f,g):
return lambda x: f(x) + g(x)
addFuncs(add1,square)(10)
Python doesn't support adding functions together which both of your attempts tried to do. Instead, you need to create a new function, such as with lambda which calls the original functions.
Your original idea will work if you instead call these functions and then add their return values, rather than trying to add them themselves;
def addFuncs(f,g,x):
f(x) + g(x)
This is because f and g are actually LambdaTypes, and the () operator calls them, allowing the + operator to add their return values. When you use the + operator on them directly, the + operator doesn't know how to add two LambdaTypes.
EDIT
To add a little more; the reason
def addFunctions(f, g):
def getf():
return f
def getg():
return g
return getf() + getg()
doesn't work is because you are, again, trying to add together two function objects. However, your example of
def addFunctions(f, g):
return f
WILL work, because this will simply return another function object, which is then called with an argument of value 10 in your statement
addFuncs(add1,square)(10)
addFuncs takes arbitrarily many functions as input and returns a function:
def addFuncs(*funcs):
def _addFuncs(*args):
return sum(f(*args) for f in funcs)
return _addFuncs
add1 = lambda x: x+1
square = lambda x: x*x
print(addFuncs(add1,square)(10))
yields
111