Function as argument for another function - python

The first function adds two numbers, the second function adds them twice. What is the purpose of Z? I get that x and y are the numbers you're adding together. But what is Z?
def add(x, y):
return x + y
def twice(z, x, y):
return z(z(x, y), z(x, y))
a = 5
b = 10
print(twice(add, a, b))

z represents the function that you want to execute twice. In your example:
twice(add, a, b)
twice received three arguments, add, a, and b. add is a reference to the add function, and becomes z instead the twice function. You might imagine a scenario in which you pass a different hypothetical function subtract to twice.

In twice(z, x, y), z is a function. So when you call twice(add, a, b), z is the function add. Therefore return z(z(x, y), z(x, y)) would be
return add(add(a, b), add(a, b))
So it calculates (a + b) + (a + b).
If you pass, for example, a function sub = lambda x, y: x - y, then twice(sub, a, b) will return sub(sub(a, b), sub(a, b)) instead, i.e., (a - b) - (a - b).
Another example:
print(twice(lambda x, y: x + ' ' + y, 'hello', 'world'))
# hello world hello world

Related

'NoneType' object is not iterable - where is an error?

My aim is to take a triple (A, B, C), compute three "neighbours", and then output the maximum of each of those neighbours to a list.
For example, the neighbours of (sqrt(6), 4*sqrt(3), 9*sqrt(2)) are
(sqrt(3)*sqrt(2), 3*sqrt(2), 4*sqrt(3))
(4*sqrt(3), 35*sqrt(3)*sqrt(2), 9*sqrt(2))
(sqrt(3)*sqrt(2), 9*sqrt(2), 14*sqrt(3))
so the values 14*sqrt(3), 36*sqrt(6), 4*sqrt(3) would be the output.
When I try this:
A = 1*sqrt(6)
B = 4*sqrt(3)
C = 9*sqrt(2)
def nbhs_1(triple):
X = triple[0]
Y = triple[1]
Z = triple[2]
print((X.canonicalize_radical(), (X * Y - Z).canonicalize_radical(), Y.canonicalize_radical()))
def nbhs_2(triple):
X = triple[0]
Y = triple[1]
Z = triple[2]
print((Y.canonicalize_radical(), (Y * Z - X).canonicalize_radical(), Z.canonicalize_radical()))
def nbhs_3(triple):
X = triple[0]
Y = triple[1]
Z = triple[2]
print((X.canonicalize_radical(), Z.canonicalize_radical(), (X * Z - Y).canonicalize_radical()))
result_1 = nbhs_1((A, B, C))
result_2 = nbhs_2((A, B, C))
result_3 = nbhs_3((A, B, C))
print(result_1)
print(result_2)
print(result_3)
l = [max(result_1), max(result_2), max(result_3)]
I get 'NoneType' object is not iterable.
The main problem is that you are not structuring the function properly:
It is recommended that you expose your arguments within the function call. Don't def nbhs_1(triple), do instead def nbhs_1(X, Y, Z). In this way you can actually have one single function that does what you want (easier to maintain)
Return your result. At the moment you are printing the outcome of the function call but you are not returning those results.
I'm also not sure the canonicalize_radical() call is also done properly. Python is object-oriented and by writing var.canonicalize_radical() you are inferring that var should itself know about this function (e.g. the function is part of var) but that sounds wrong. The correct call may be canonicalize_radical(var)
Basically, this should be closer to a correct solution:
A=1*sqrt(6)
B=4*sqrt(3)
C=9*sqrt(2)
def nbhs(X, Y, Z):
out1 = canonicalize_radical(X)
out2 = canonicalize_radical(X*Y-Z)
out3 = canonicalize_radical(Y)
return out1, out2, out3
l = [max(nbhs(A, B, C)), max(nbhs(B, A, C)), max(nbhs(C, B, A))]
The problem is that you are not calling the functions nbhs_1, nbhs_2, and nbhs_3 and also the functions aren't returning any values
from math import sqrt
A=1*sqrt(6)
B=4*sqrt(3)
C=9*sqrt(2)
triple = (A, B, C)
def nbhs_1(triple):
X=triple[0]
Y=triple[1]
Z=triple[2]
return (X.canonicalize_radical(),(X*Y-Z).canonicalize_radical(),Y.canonicalize_radical())
def nbhs_2(triple):
X=triple[0]
Y=triple[1]
Z=triple[2]
return (Y.canonicalize_radical(),(Y*Z-X).canonicalize_radical(),Z.canonicalize_radical())
def nbhs_3(triple):
X=triple[0]
Y=triple[1]
Z=triple[2]
return (X.canonicalize_radical(),Z.canonicalize_radical(),(X*Z-Y).canonicalize_radical())
l=[max(nbhs_1(triple)),max(nbhs_2(triple)),max(nbhs_3(triple))]

python futures and tuple unpacking

What is an elagant/idiomatic way to achieve something like tuple unpacking with futures?
I have code like
a, b, c = f(x)
y = g(a, b)
z = h(y, c)
and I would like to convert it to use futures.
Ideally I would like to write something like
a, b, c = ex.submit(f, x)
y = ex.submit(g, a, b)
z = ex.submit(h, y, c)
The first line of that throws
TypeError: 'Future' object is not iterable
though.
How can I get a,b,c without having to make 3 additional ex.submit calls? ie. I would like to avoid having to write this as:
import operator as op
fut = ex.submit(f, x)
a = client.submit(op.getitem, fut, 0)
b = client.submit(op.getitem, fut, i)
c = client.submit(op.getitem, fut, 2)
y = ex.submit(g, a, b)
z = ex.submit(h, y, c)
I guess a potential solution is to write an unpack function like below,
import operator as op
def unpack(fut, n):
return [client.submit(op.getitem, fut, i) for i in range(n)]
a, b, c = unpack(ex.submit(f, x), 3)
y = ex.submit(g, a, b)
z = ex.submit(h, y, c)
which works: for example if you first define:
def f(x):
return range(x, x+3)
x = 5
g = op.add
h = op.mul
then you get
z.result() #===> 77
I thought something like this might already exist.
The above only works with dask.distributed.Future. It does not work for plain concurrent.futures.Future.
A quick glance at:
https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Future
suggests that you'll have to do something like
afuture = ex.submit(f, x)
a,b,c = afuture.result()
...
submit returns a Future object, not the result of running f(x).
This SO answer indicates that chaining futures is not trivial:
How to chain futures in a non-blocking manner? That is, how to use one future as an input in another future without blocking?

scale translate function with python decorator

I have a list of single parameter functions in python to which I would like to apply the same scaling/translation operation.
The scale/translation for a function f(x) would be as follows:
f'(x, a, b, c, d) = a + b* f( c*(x - d) )
So for example if my original function is defined as:
f(x) = 3*x
I would like to modify it to be:
f'(x, a, b, c, d) = a + b * (3*(c*(x - d)))
Ideally using a decorator (or some other reusable operation that I can apply to each function in the list).
Is there a pythonic way to achieve this such that every transformation doesn't need to be hardcoded for each function I have?
Apologies if the question is unclear - thanks in advance for any suggestions.
def f(x):
return 3*x
def makeFPrime(func):
def inner(x, a, b, c, d):
return a + b * (3*(c*func(x-d)))
return inner
This gives for example:
f2 = makeFPrime(f)
f2(2,1,1,1,2)
1
f2(2,1,1,1,0)
19
Alternatively, use makeFPrime as a decorator:
def makeFPrime(func):
def inner(x, a, b, c, d):
return a + b * (3*(c*func(x-d)))
return inner
#makeFPrime
def f(x):
return 3*x
Then f(2,1,1,1,2) returns 1

SymPy: Evaluate given expression with given variables

I have a sympy expression involving two variables a, b. I would now like to evaluate this expression for specific values of a and b. Using a lambda like
import sympy
def get_expression(a, b):
# Complex function with a simple result. I have no control here.
return a*b + 2
a = sympy.Symbol('a')
b = sympy.Symbol('b')
z = get_expression(a, b)
f = lambda a, b: z
print(f(1, 1))
only gives
a*b + 2
though.
Any hints?
Turns out that lambdify is what I need:
f = sympy.lambdify([a, b], z)
print(f(1, 1))

Python lambda used as an argument, calling other arguments from parent function

I'm new to programming and am having a little trouble understanding the lambda function in Python. I understand why it's used and its effectiveness. Just having trouble learning to apply it. I've read a guide and watched a lecture on using lambda as an argument. I've tried using the map function. Not sure if that's the correct approach, but this is my broken code in its most basic form:
def Coord(x, y, z=lambda: z*2 if z < x or z < y else z)):
print(z)
Coord(10,20,30)
Coord(10,20,12)
Coord(10,20,8)
Needs to return 30, 24, and 32, respectively.
Working code without using lambda:
def Coord(x, y, z):
while z < x or z < y:
z*=2
print(z)
You cannot use other parameters from the Coord function in your default parameter definition for z (which is a lambda function in your case).
You may want to do something like this:
def Coord(x, y, w, z=lambda a,b,c: c*2 if c < a or c < b else c):
print(z(x,y,w))
or
def Coord(x, y, w):
z=lambda: w*2 if w < x or w < y else w
print(z())
Both definitions are equivalent when evaluating them with 3 arguments, and they result in:
>>> Coord(10,20,30)
30
>>> Coord(10,20,12)
24
>>> Coord(10,20,8)
16

Categories

Resources