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)
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 am new to python and I am trying to understand the logic here:
What does lambda x=x mean? in the complete function below:
tables = [lambda x=x: x*10 for x in range(1, 11)]
for table in tables:
print(table())
There are two different variables named x here.
The first one is the parameter, which is a local variable in the function being defined.
The second is a variable visible in the scope where the function is being defined. Its value is stored as the default value to use for the first variable x if no argument is passed when the function is called.
It is far less confusing if you just use two different names for the two different variables:
tables = [lambda x=y: x*10 for y in range(1, 11)]
This is the short way of writing
tables = []
tables.append(lambda x=1: x*10)
tables.append(lambda x=2: x*10)
# etc.
Based on how each function is called in the following loop, the intention appears to be to never actually pass an argument when the function is called, and that what we really want is to automate something like
tables = []
tables.append(lambda : 1 * 10)
tables.append(lambda : 2 * 10)
# etc.
The naive approach
tables = [lambda: x*10 for x in range(1, 11)]
fails because x is a free variable in the body of the function; it does not get replaced with the value of x at the time the function is called. Doing this, you end up with a list of 10 identical function, all of which depend on the last value assigned to x before the function is called.
By binding a default value that is evaluated immediately to the parameter, you "inject" the current value of x into the function right away, so that you end up with a list of 10 different functions.
tables = [lambda y = x: x*10 for x in range(1, 11)]
for table in tables:
print(table())
The output is 10 100s printed one below the other
I an unable to understand the logic
I'm looking for a way to change the variables defined inside a function after defining the function.
For example
def GetNthPower(x) :
n = None
return x**n
my_numbers_list = [11,23,45,56,78,98]
# now if I feel like I need the 4th power of some numbers in the list
GetNthPower.n = 4
for x in my_numbers_list :
print GetNthPower(x)
# If I want 7th power then
GetNthPower.n = 7
This obviously will not work, is there any way to do this?
N.B: I know we can achieve this by setting 'n' as an argument of the function, but I want to do it this way for a particular reason.
I want my function to have only one argument (for using the function in multiprocessing.Pool.map()).
You can define static variables inside functions, almost like you did:
def GetNthPower(x) :
return x ** GetNthPower.n
GetNthPower.n = 3
print(GetNthPower(2)) #8
Make sure to initialize correctly your GetNthPower.n before first use though.
If you're worried about initialization, you could go for this version which uses a default value 1:
def GetNthPower(x) :
return x ** (GetNthPower.n if hasattr(GetNthPower, "n") else 1)
I think it would still be better for you to write a function that takes two arguments, or use the predefined ** operator.
Don't use one function; create a function that makes your function, using a closure.
def nth_power_maker(n):
def _(x):
return x ** n
return _
my_numbers_list = [11,23,45,56,78,98]
# now if I feel like I need the 4th power of some numbers in the list
get_4th_power = nth_power_maker(4)
for x in my_numbers_list:
print(get_4th_power(x))
get_7th_power = nth_power_maker(7)
Alternatively, you could use functools.partial to bind a keyword argument to a function
from functools import partial
def get_nth_power(x, n):
return x ** n
get_third = partial(get_nth_power, n=3)
get_third(4)
64
x = 4
# in a loop
for pow in [2, 4, 6, 8]:
f = partial(get_nth_power, n=pow)
f(x)
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.
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))