If I have a very simple (although possibly very complex) function generator in Python 2.7, like so:
def accumulator():
x = yield 0
while True:
x += yield x
Which can be used, like so:
>>> a = accumulator()
>>> a.send(None)
0
>>> a.send(1)
1
>>> a.send(2)
3
>>> a.send(3)
6
What would be a simple wrapper for another function generator that produces the same result, except multiplied by 2? The above function generator is simple, but please assume it is too complicated to copy-paste. I'm trying something, like:
def doubler():
a = accumulator()
a.send(None)
y = yield 0
while True:
y = 2 * a.send(yield y)
Or, imagining something simpler:
def doubler():
a = accumulator()
a.send = lambda v: 2 * super(self).send(v)
return a
Both of which are horribly broke, so I won't share the syntax errors, but it may illustrate what I'm trying to do.
Ideally, I would like to get something, like:
>>> d = doubler()
>>> d.send(None)
0
>>> d.send(1)
2
>>> d.send(2)
6
>>> d.send(3)
12
The results are the exact same as the original, except doubled.
I'm trying to avoid duplicating a very complicated function generator to create an identical result, except scaled by a known factor.
The second generator will ultimately have a different input stream, so I cannot just use the result from the first generator and double it. I need a second independent generator, wrapping the first.
The input stream is indeterminate, such that it is impossible to generate the entire sequence and then transform.
It seems I want to map or nest these function generators, but I'm not sure of the appropriate jargon, and so I'm getting nowhere in Google.
If you need to have the same interface as a coroutine (i.e. have a send method), then BrenBarn's solution is probably as simple as it gets.*
If you can have a slightly different interface, then a higher-order function is even simpler:
def factor_wrapper(coroutine, factor):
next(coroutine)
return lambda x, c=coroutine, f=factor: f * c.send(x)
You would use it as follows:
>>> a = accumulator()
>>> a2 = factor_wrapper(a, 2)
>>> print a2(1)
2
>>> print a2(2)
6
>>> print a2(3)
12
*Actually you can shave several lines off to make it 4 lines total, though not really reducing complexity much.
def doubler(a):
y = yield next(a)
while True:
y = yield (2 * a.send(y))
or even shorter...
def doubler(a, y=None):
while True:
y = yield 2 * a.send(y)
Either of the above can be used as follows:
>>> a = accumulator()
>>> a2 = doubler(a)
>>> print a2.send(None) # Alternatively next(a2)
0
>>> print a2.send(1)
2
>>> print a2.send(2)
6
>>> print a2.send(3)
12
I didn't tried this, but something along these lines:
class Doubler:
def __init__(self, g):
self.g = g()
def __next__(self):
return self.send(None)
def send(self, val):
return self.g.send(val)*2
Also, after Python 3.5, extending this from collections.abc.Container will eliminate the need of __next__, also will make this a proper generator(It currently doesn't support __throw__ etc., but they're just boilerplate).
Edit: Yes, this works:
In [1]: %paste
def accumulator():
x = yield 0
while True:
x += yield x
## -- End pasted text --
In [2]: %paste
class Doubler:
def __init__(self, g):
self.g = g()
def __next__(self):
return self.send(None)
def send(self, val):
return self.g.send(val)*2
## -- End pasted text --
In [3]: d = Doubler(accumulator)
In [4]: d.send(None)
Out[4]: 0
In [5]: d.send(1)
Out[5]: 2
In [6]: d.send(2)
Out[6]: 6
In [7]: d.send(3)
Out[7]: 12
You just need to move the yield outside the expression that passes y to a:
def doubler():
a = accumulator()
next(a)
y = yield 0
while True:
y = yield (2 * a.send(y))
Then:
>>> a = accumulator()
... d = doubler()
... next(a)
... next(d)
... for i in range(10):
... print(a.send(i), d.send(i))
0 0
1 2
3 6
6 12
10 20
15 30
21 42
28 56
36 72
45 90
I think this is what you want:
def doubler():
a = accumulator()
y = a.send(None)
x = yield 0
while True:
y = a.send(x)
x = yield 2 * y
This completely wraps the accumulator implementation but you could alternatively make that visible and pass it in as a parameter a to doubler.
Related
When my function foo generating a new element, I want to reuse the output and put it in foo n-times. How can I do it?
My function:
def foo(x):
return x + 3
print(foo(1))
>>>4
For now. I'm using this method:
print(foo(foo(foo(1))))
There are a couple ways to do what you want. First is recursion, but this involves changing foo() a bit, like so:
def foo(x, depth):
if depth <= 0:
return x
return foo(x+3, depth-1)
and you'd call it like foo(1, n)
The other way is with a loop and temp variable, like so
val = 1
for _ in range(0, n):
val = foo(val)
Use a loop for this:
value = 1
for i in range(10):
value = foo(value)
def foo(x,y):
for i in range(y):
x = x + 3
return x
print (foo(10,3))
Output:
19
What you are searching for is called recursion:
def foo(x, n=1):
if n == 0:
return x
return foo(x + 3, n - 1)
Another possible with lambda and reduce
Reduce function
from functools import reduce
def foo(x):
return x + 3
print(reduce(lambda y, _: foo(y), range(3), 1))
You will get 10 as result
# y = assigned return value of foo.
# _ = is the list of numbers from range(3) for reduce to work
# 3 = n times
# 1 = param for x in foo
I know how to compose two functions by taking two functions as input and output its composition function but how can I return a composition function f(f(...f(x)))? Thanks
def compose2(f, g):
return lambda x: f(g(x))
def f1(x):
return x * 2
def f2(x):
return x + 1
f1_and_f2 = compose2(f1, f2)
f1_and_f2(1)
You use a loop, inside a nested function:
def compose(f, n):
def fn(x):
for _ in range(n):
x = f(x)
return x
return fn
fn will be have closure that retains references to the f and n that you called compose with.
Note this is mostly just copied from https://stackoverflow.com/a/16739439/2750819 but I wanted to make it clear how you can apply it for any one function n times.
def compose (*functions):
def inner(arg):
for f in reversed(functions):
arg = f(arg)
return arg
return inner
n = 10
def square (x):
return x ** 2
square_n = [square] * n
composed = compose(*square_n)
composed(2)
Output
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
if you want to make it one line composition,
then try this,
def f1(x):
return x * 2
def f2(x):
return x + 1
>>> out = lambda x, f=f1, f2=f2: f1(f2(x)) # a directly passing your input(1) with 2 function as an input (f1, f2) with default so you dont need to pass it as an arguments
>>> out(1)
4
>>>
>>> def compose(f1, n):
... def func(x):
... while n:
... x = f1(x)
... n = n-1
... return x
... return func
>>> d = compose(f1, 2)
>>> d(2)
8
>>> d(1)
4
>>>
you can use functools.reduce:
from functools import reduce
def compose(f1, f2):
return f2(f1)
reduce(compose, [1, f2, f1]) # f1(f2(1))
output:
4
if you want to compose same function n times:
n = 4
reduce(compose, [1, *[f1]*n]) # f1(f1(f1(f1(1))))
output:
16
I'm attempting to create a random quadratic function to the 2nd degree in python that returns the same result every time.
Something along the lines of:
funk = lambda i : random.randint(0,10)*i**2 + random.randint(0,10)*i + random.randint(0,10)
The problem here is that calling x(5) two different times will have 2 potentially different results. Is it possible to generate a function that has the same result every time, or should I just do something like:
m2 = random.randint(0,9)
m1 = random.randint(0,9)
b = random.randint(0,9)
funk = lambda i : m2*i**2 + m1*i + b
and assign a new random number to globals m2,m1, and b every time I run it?
You need to randomize coefficients only once, then save them somewhere and reuse for the following computations of the same function.
A class instance is ideal for this:
class RandomQuadratic:
def __init__(self):
self.a = random.randint(0,10)
self.b = random.randint(0,10)
self.c = random.randint(0,10)
def __call__(self,x):
return self.a*x**2+self.b*x+self.c
f = RandomQuadratic()
f(5)
f(5)
Do the second approach, but just chuck it into a function. :)
>>> import random
>>> def random_quadratic():
... m2 = random.randint(0,9)
... m1 = random.randint(0,9)
... b = random.randint(0,9)
... funk = lambda i : m2*i**2 + m1*i + b
... return funk
...
>>> foo = random_quadratic()
>>> foo(1)
25
>>> foo(1)
25
>>> foo(1)
25
>>> foo(2)
55
>>> foo(2)
55
>>> foo(2)
55
>>> foo(3)
99
>>> foo(3)
99
>>> foo(3)
99
>>>
In this example (which does not work)
def foo(x,y):
x = 42
y = y * 2
x = 0
y = 2
foo(x,y)
I would like x = 42 and y = 4.
The idea behind is to have a wrapper to C functions using ctypes:
def foo(self, x, y):
error = self.dll.foo(self.handler, x, pointer(y))
if error:
self.exception(error)
How can I pass parameters as references in Python?
Like #musically_ut, you cannot pass primitive values by reference, but you can get newest values by returning from function. Like this:
def foo(x,y):
x = 42
y = y * 2
return x,y
x = 0
y = 2
x,y=foo(x,y)
Say I have a function that calculates and returns an value:
h = 4.13566733*10**-15
c = 2.99792458*10**(8+9)
def func(x):
for i in w:
A = h*c/i
return A
w = [1]
print func(w)
Fine. But if w is a larger array, say:
w = [1 ,2, 3, 4]
The func returns for the last value in w (4). Understandebly as that is the last item in the for-loop.
But how can I make the func return an array with all 4 values, something like:
[1239, 619, 413, 309]
??
Python supports passing multiple arguments, and returning multiple values. That said, you can change your code to:
def func(w):
return [h*c/i for i in w]
If you now call this, you can get the required array:
>>> w = [1 ,2, 3, 4]
>>> func(w)
[1239.8418743309974, 619.9209371654987, 413.2806247769991, 309.96046858274934]
As for calling with multiple arguments and returning multiple examples, consider the following example method, which takes 2 inputs and returns 3 outputs:
>>> def get_product_modulo_dividend(x, y):
... return x*y, x%y, x/y
>>> get_product_modulo_dividend(100, 10)
(1000, 0, 10)
Make your A a list and append each result to that list
h = 4.13566733*10**-15
c = 2.99792458*10**(8+9)
def func(x):
A = []
for i in w:
A.append(h*c/i)
return A
w = [1,2,3,4]
print func(w)
This outputs:
[1239.8418743309974, 619.92093716549869, 413.2806247769991, 309.96046858274934]
this is similar to what at #mu posted, but it seems like your function is operating on single values that are not connected together and might be more flexible implemented as only taking a number as a param.
h = 4.13566733*10**-15
c = 2.99792458*10**(8+9)
def func(x):
return h*c / x
w = [1,2,3,4]
print([func(x) for x in w])
You can use map, for example.
h = 4.13566733*10**-15
c = 2.99792458*10**(8+9)
def func(x):
return h*c/x
w = [1,2,3]
print map(func, w)
Will return [1239.8418743309974, 619.9209371654987, 413.2806247769991]
And you can use more elegant way (as for me):
h = 4.13566733*10**-15
c = 2.99792458*10**(8+9)
w = [1,2,3]
result = map(lambda (x): h*c/x, w)
Is returns also [1239.8418743309974, 619.9209371654987, 413.2806247769991].