I have an algorithm that can generate a prime list as a generator:
def _odd_iter():
n=3
while True:
yield n
n=n+2
def _not_divisible(n):
return lambda x: x % n > 0
def primes():
yield 2
L=_odd_iter()
while True:
n=next(L)
yield n
L=filter(_not_divisible(n), L)
x=1
for t in primes():
print(t)
x=x+1
if x==10:
break
But if I put the lambda function into the filter function directly, like below:
def primes():
yield 2
L=_odd_iter()
while True:
n=next(L)
yield n
L=filter(lambda x: x%n>0, L)
I can get only an odd list, not a prime list. It seems the filter function doesn't work.
What can I do?
Here's a simpler program which illustrates the same problem.
adders = []
for i in range(4):
adders.append(lambda a: i + a)
print(adders[0](3))
While one would expect the output to be 3, the actual output is 6.
This is because a closure in python remembers the name and scope of a variable rather than it's value when the lambda was created. Since, i has been modified by the time the lambda is used, the lambda uses the latest value of i.
The same thing happens in your function. Whenever n is modified, all the lambda functions in the various filters also get modified. So, by the time the iterator reaches 9, all the filters are filtering factors of 7, not 5 or 3.
Since, in your first approach you are creating a new scope with each call to _not_divisible, the function works as intended.
If you absolutely must use a lambda directly, you can use a second argument like this:
def primes():
yield 2
L=_odd_iter()
while True:
n=next(L)
yield n
L=filter(lambda x, n=n: x%n>0, L)
The lambda that works is lambda x, n=n: x%n != 0. You apparently need to do this if you want n to be captured at the time the lambda is defined. Otherwise a lambda only looks up the variable name when it gets around to evaluating the lambda. In your case I think that meant locking onto an n value in a later iteration of the while loop.
Related
I have a pipeline function that takes an arbitrary number of functions as arguments, it returns a single function helper which contain one argument and this function in turn calls the pipeline function with a single argument iteratively. Here is the code:
def pipeline(*funcs):
def helper(arg):
for func in funcs:
result = func(arg)
arg = result
return result
return helper
And here a test case:
fun = pipeline(lambda x: x * 3, lambda x: x + 1, lambda x: x / 2)
print(fun(3)) #should print 5.0
I was reading on a different question about generators and how they can be used to remember previous state here, and was wondering if I could reframe my current pipeline function to use a generator instead. I need to remember the arg for every func call and currently I'm doing that by storing into a variable, however since generators can remember the last state I was wondering if I could use it instead.
You could (but absolutely shouldn't) create a side-effect based list-comprehension that uses the walrus-operator:
funcs = [lambda x: x * 3, lambda x: x + 1, lambda x: x / 2]
x = 3
[x := f(x) for f in funcs]
print(x)
What makes this even worse than it already is is the fact that if you use a simple generator instead of the list-comprehension the result is different because it doesn't all get executed before the print.
Or you even force it all in one line like this:
print([x := f(x if i>0 else 3) for i, f in enumerate(funcs)][-1])
I think generally a prettier approach would be to just wrap it into a normal for loop:
x = 3
for f in funcs:
x = f(x)
print(x)
I know that there are way simpler ways to calculate the square of a number and store it in an array, but for the sake of another problem. I need to understand why nothing happens in this code and its structure (is the return(a) necessary ?):
s=[1,2,3,4,5]
def square(x):
return x*x
def iterate(b):
sol=[]
for b in s:
a=square(b)
return(a)
sol.append(a)
print(sol)
The goal is to store the square in sol : sol = [1,4,9,16,25]. But the code runs without printing anything. What make the following code work and not the previous one ?
s=[1,2,3,4,5]
def square(x):
return x*x
sol=[]
for b in s:
a=square(b)
sol.append(a)
print(sol)
(My problem involves curve fitting, and this structure doesnt fit my needs)
The problem is that you define iterate within square but you never call iterate. It would be better to have iterate be a separate function that calls square:
values = [1,2,3,4,5] # do not call your variable set - it is a Python keyword
def square(x):
return x*x
def iterate(values):
solution = []
for value in values:
value_squared = square(value)
solution.append(value_squared)
return solution
You could also do this without defining iterate using a list comprehension:
[square(value) for value in values]
Edit:
To answer your other questions, here is your code:
s=[1,2,3,4,5]
def square(x):
return x*x
def iterate(b):
sol=[]
for b in s:
a=square(b)
return(a)
sol.append(a)
print(sol)
In square, you never call iterate so this part of the code never runs.
If you add a call to iterate within square, you will end up in an infinite loop. This is because within iterate you call square, but you always iterate over your list s. This means that inside iterate, square(b) will always be square(1).
Within iterate you use the global variable s but it would be better to restructure your code so that you take s as input.
If you are learning about inner functions, you could define iterate and within this define square:
values = [1,2,3,4,5]
def iterate(values):
def _square(x):
return x*x
solution = []
for value in values:
value_squared = _square(value)
solution.append(value_squared)
return solution
I am slightly confused by map in python. The function for mapaccepts 2 parameters: `map(function, variables).
Why is the code below able to take in multiply and add as variables but the second code isn't able to? In a usual case, multiply should be passed in in as a function, check out range.
def multiply(x):
return x * x
def add(x):
return x + x
funcs = [multiply, add]
for i in range (1, 5):
value = list(map(lambda x: x(i), funcs))
print(value)
This is the second code:
def multiply(x):
return x * x
def add(x):
return x + x
funcs = (add, multiply)
multi_func = (multiply)
for i in range (1, 5):
value = list(map(lambda x: x(i), multi_func))
print(value)
Is it possible to make use of 1 function and still use for in range?
Using range:
map(multiply, range(1, 5))
map applies its first argument, which is a function, to each element of the iterable which is the second argument. The function is applied lazily. That means it's done only when you iterate over the map object, e.g., when you create a list of of it.
Let's take a look at your first code. funcs = [multiply, add] creates a list, which is iterable, of two elements. Both elements are functions. This is normal in Python, because functions are just regular objects, and can be passed around, assigned, have attributes, etc. The loop
for i in range (1, 5):
value = list(map(lambda x: x(i), funcs))
print(value)
Repeats form 1 to 4. At each iteration it maps lambda x: x(i) to the functions in funcs. When i = 1, the map ends up doing multiply(1), add(1). When i = 2, it's multiply(2), add(2), and so on.
The second code doesn't work because of a typo. (x) is just x, but (x,) is a one-element tuple whose first element is x. map requires the second argument to be iterable, so passing in a function won't do. If you want to map to a single function, you need to supply an iterable with one element: multi_func = (multiply,).
Once corrected, the second version will print multiply(1) when i = 1, multiply(2) when i = 2, etc.
Something like list(map(multiply, range(1, 5))) will in fact be an easier way to write the second version. You can also do something similar with the first code, using zip:
zip(map(func, range(1, 5)) for func in funcs)
I have come across this example from Python hitchhikers guide:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
The example above is the solution to some issues caused with late binding, where variables used in closures are looked up at the time the inner function is called.
What does the i=i mean and why is it making such difference?
It's actually not just for lambdas; any function that takes default parameters will use the same syntax. For example
def my_range(start, end, increment=1):
ans = []
while start < end:
ans.append(start)
start += increment
return ans
(This is not actually how range works, I just thought it would be a simple example to understand). In this case, you can call my_range(5,10) and you will get [5,6,7,8,9]. But you can also call my_range(5,10,increment=2), which will give you [5, 7, 9].
You can get some surprising results with default arguments. As this excellent post describes, the argument is bound at function definition, not at function invocation as you might expect. That causes some strange behavior, but it actually helps us here. Consider the incorrect code provided in your link:
def create_multipliers():
return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
print multiplier(2)
When you call multiplier(2), what is it actually doing? It's taking your input parameter, 2, and returning i * 2. But what is i? The function doesn't have any variable called i in its own scope, so it checks the surrounding scope. In the surrounding scope, the value of i is just whatever value you left it -- in this case 4. So every function gives you 8.
On the other hand, if you provide a default parameter, the function has a variable called i in its own scope. What's the value of i? Well, you didn't provide one, so it uses its default value, which was bound when the function was defined. And when the function was defined, i had a different value for each of the functions in your list!
It is a bit confusing that they've used the same name for the parameter variable as they did for the iterating variable. I suspect you could get the same result with greater readability with
def create_multipliers():
return [(lambda x, y=i: y*x) for i in range(5)]
In that case, each number in the range, will be assigned to the optional parameters of each lambda function:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
lambda x, i=0
lambda x, i=1
lambda x, i=2
lambda x, i=3
lambda x, i=4
So, you can call the functions now with one parameter (because they already have the default)
for f in create_multipliers():
print(f(3))
0
3
6
9
12
Or you can call the function and give the parameter you want, that's why is optional
for f in create_multipliers():
print(f(3,2))
6
6
6
6
6
There are examples where optional parameter are needed, such as recursion
For example, square in terms of square:
square = lambda n, m=0: 0 if n==m else n+square(n,m+1)
Look that the optional parameter there is used as accumulator
I have foreach function which calls specified function on every element which it contains. I want to get minimum from thise elements but I have no idea how to write lambda or function or even a class that would manage that.
Thanks for every help.
I use my foreach function like this:
o.foreach( lambda i: i.call() )
or
o.foreach( I.call )
I don't like to make a lists or other objects. I want to iterate trough it and find min.
I manage to write a class that do the think but there should be some better solution than that:
class Min:
def __init__(self,i):
self.i = i
def get_min(self):
return self.i
def set_val(self,o):
if o.val < self.i: self.i = o.val
m = Min( xmin )
self.foreach( m.set_val )
xmin = m.get_min()
Ok, so I suppose that my .foreach method is non-python idea. I should do my Class iterable because all your solutions are based on lists and then everything will become easier.
In C# there would be no problem with lambda function like that, so I though that python is also that powerful.
Python has built-in support for finding minimums:
>>> min([1, 2, 3])
1
If you need to process the list with a function first, you can do that with map:
>>> def double(x):
... return x * 2
...
>>> min(map(double, [1, 2, 3]))
2
Or you can get fancy with list comprehensions and generator expressions, for example:
>>> min(double(x) for x in [1, 2, 3])
2
You can't do this with foreach and a lambda. If you want to do this in a functional style without actually using min, you'll find reduce is pretty close to the function you were trying to define.
l = [5,2,6,7,9,8]
reduce(lambda a,b: a if a < b else b, l[1:], l[0])
Writing foreach method is not very pythonic. You should better make it an iterator so that it works with standard python functions like min.
Instead of writing something like this:
def foreach(self, f):
for d in self._data:
f(d)
write this:
def __iter__(self):
for d in self._data:
yield d
Now you can call min as min(myobj).
I have foreach function which calls specified function on every element which it contains
It sounds, from the comment you subsequently posted, that you have re-invented the built-in map function.
It sounds like you're looking for something like this:
min(map(f, seq))
where f is the function that you want to call on every item in the list.
As gnibbler shows, if you want to find the value x in the sequence for which f(x) returns the lowest value, you can use:
min(seq, key=f)
...unless you want to find all of the items in seq for which f returns the lowest value. For instance, if seq is a list of dictionaries,
min(seq, key=len)
will return the first dictionary in the list with the smallest number of items, not all dictionaries that contain that number of items.
To get a list of all items in a sequence for which the function f returns the smallest value, do this:
values = map(f, seq)
result = [seq[i] for (i, v) in enumerate(values) if v == min(values)]
Okay, one thing you need to understand: lambda creates a function object for you. But so does plain, ordinary def. Look at this example:
lst = range(10)
print filter(lambda x: x % 2 == 0, lst)
def is_even(x):
return x % 2 == 0
print filter(is_even, lst)
Both of these work. They produce the same identical result. lambda makes an un-named function object; def makes a named function object. filter() doesn't care whether the function object has a name or not.
So, if your only problem with lambda is that you can't use = in a lambda, you can just make a function using def.
Now, that said, I don't suggest you use your .foreach() method to find a minimum value. Instead, make your main object return a list of values, and simply call the Python min() function.
lst = range(10)
print min(lst)
EDIT: I agree that the answer that was accepted is better. Rather than returning a list of values, it is better to define __iter__() and make the object iterable.
Suppose you have
>>> seq = range(-4,4)
>>> def f(x):
... return x*x-2
for the minimum value of f
>>> min(f(x) for x in seq)
-2
for the value of x at the minimum
>>> min(seq, key=f)
0
of course you can use lambda too
>>> min((lambda x:x*x-2)(x) for x in range(-4,4))
-2
but that is a little ugly, map looks better here
>>> min(map(lambda x:x*x-2, seq))
-2
>>> min(seq,key=lambda x:x*x-2)
0
You can use this:
x = lambda x,y,z: min(x,y,z)
print(x(3,2,1))