Probably easier to use list comprehensions:
print (lambda w, x=10, y=range(10):\
[(0 if (i >= w*w and i < x and i%w==0) else n) for i, n in enumerate(y)])(2)
Moved to two lines for readability, but you can delete the \ and the line break and it will run fine.
One caveat is that this doesn't alter the original list, but returns a new one.
If you needed it to update the original list AND return it, you could use short-circuiting:
print (lambda w, x=10, y=range(10):\
([y.__setitem__(i, 0) for i in range(w*w, x, w)] and y))(2)
Correction:
The code above works only if range(w*w, x, w) is non-empty, i.e. w*w > x, which is a weak condition.
The following corrects for this issue:
print (lambda w, x=10, y=range(10):\
(([y.__setitem__(i, 0) for i in range(w*w, x, w)] or 1) and y))(2)
This uses the fact that (a or 1) and b always evaluates to b after the value of a gets evaluated.
Probably easier to use list comprehensions:
print (lambda w, x=10, y=range(10):\
[(0 if (i >= w*w and i < x and i%w==0) else n) for i, n in enumerate(y)])(2)
Moved to two lines for readability, but you can delete the \ and the line break and it will run fine.
One caveat is that this doesn't alter the original list, but returns a new one.
If you needed it to update the original list AND return it, you could use short-circuiting:
print (lambda w, x=10, y=range(10):\
([y.__setitem__(i, 0) for i in range(w*w, x, w)] and y))(2)
Correction:
The code above works only if range(w*w, x, w) is non-empty, i.e. w*w > x, which is a weak condition.
The following corrects for this issue:
print (lambda w, x=10, y=range(10):\
(([y.__setitem__(i, 0) for i in range(w*w, x, w)] or 1) and y))(2)
This uses the fact that (a or 1) and b always evaluates to b after the value of a gets evaluated.
Here's a pure lambda implementation, which takes w, x, and y as arguments to a top-level lambda:
>>> (lambda w,x,y: (lambda s: map(lambda v: 0 if v in s else v, y))(set(range(w*w,x,w))))(2,10,range(10))
[0, 1, 2, 3, 0, 5, 0, 7, 0, 9]
>>>
Note that this avoids the use of __setitem__.
Issue with creating lambda functions using for loop
python - Lambda function in list comprehensions - Stack Overflow
Python Lambda Count/Loop Function - Stack Overflow
python - Lambda in a loop - Stack Overflow
Videos
Just in case, if someone is looking for a similar problem...
Most solutions given here are one line and are quite readable and simple. Just wanted to add one more that does not need the use of lambda(I am assuming that you are trying to use lambda just for the sake of making it a one line code). Instead, you can use a simple list comprehension.
[print(i) for i in x]
BTW, the return values will be a list of Nones.
Since a for loop is a statement (as is print, in Python 2.x), you cannot include it in a lambda expression. Instead, you need to use the write method on sys.stdout along with the join method.
x = lambda x: sys.stdout.write("\n".join(x) + "\n")
Hey all,
Can someone explain why when I run the below code:
arr = []
for n in range(1,5):
arr.append(lambda n: 5+n)
I can't run one of the functions in the array by simply calling arr[0]()with empty parenthesis?
it throws an error saying I need to pass one positional argument, n - but I'm passing it using for loop, am I not?
There is evidently something I'm missing.
What makes it worse to me is that ok, if I pass an argument, say I will call art[0](7) - that makes the n in my lambda and in for loop useless, because the value (of n) didn't get passed at all to that lambda n: definition...
Any help would be appreciated!
The first one creates a single lambda function and calls it ten times.
The second one doesn't call the function. It creates 10 different lambda functions. It puts all of those in a list. To make it equivalent to the first you need:
[(lambda x: x*x)(x) for x in range(10)]
Or better yet:
[x*x for x in range(10)]
This question touches a very stinking part of the "famous" and "obvious" Python syntax - what takes precedence, the lambda, or the for of list comprehension.
I don't think the purpose of the OP was to generate a list of squares from 0 to 9. If that was the case, we could give even more solutions:
squares = []
for x in range(10): squares.append(x*x)
- this is the good ol' way of imperative syntax.
But it's not the point. The point is W(hy)TF is this ambiguous expression so counter-intuitive? And I have an idiotic case for you at the end, so don't dismiss my answer too early (I had it on a job interview).
So, the OP's comprehension returned a list of lambdas:
[(lambda x: x*x) for x in range(10)]
This is of course just 10 different copies of the squaring function, see:
>>> [lambda x: x*x for _ in range(3)]
[<function <lambda> at 0x00000000023AD438>, <function <lambda> at 0x00000000023AD4A8>, <function <lambda> at 0x00000000023AD3C8>]
Note the memory addresses of the lambdas - they are all different!
You could of course have a more "optimal" (haha) version of this expression:
>>> [lambda x: x*x] * 3
[<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>]
See? 3 time the same lambda.
Please note, that I used _ as the for variable. It has nothing to do with the x in the lambda (it is overshadowed lexically!). Get it?
I'm leaving out the discussion, why the syntax precedence is not so, that it all meant:
[lambda x: (x*x for x in range(10))]
which could be: [[0, 1, 4, ..., 81]], or [(0, 1, 4, ..., 81)], or which I find most logical, this would be a list of 1 element - a generator returning the values. It is just not the case, the language doesn't work this way.
BUT What, If...
What if you DON'T overshadow the for variable, AND use it in your lambdas???
Well, then crap happens. Look at this:
[lambda x: x * i for i in range(4)]
this means of course:
[(lambda x: x * i) for i in range(4)]
BUT it DOESN'T mean:
[(lambda x: x * 0), (lambda x: x * 1), ... (lambda x: x * 3)]
This is just crazy!
The lambdas in the list comprehension are a closure over the scope of this comprehension. A lexical closure, so they refer to the i via reference, and not its value when they were evaluated!
So, this expression:
[(lambda x: x * i) for i in range(4)]
IS roughly EQUIVALENT to:
[(lambda x: x * 3), (lambda x: x * 3), ... (lambda x: x * 3)]
I'm sure we could see more here using a python decompiler (by which I mean e.g. the dis module), but for Python-VM-agnostic discussion this is enough.
So much for the job interview question.
Now, how to make a list of multiplier lambdas, which really multiply by consecutive integers? Well, similarly to the accepted answer, we need to break the direct tie to i by wrapping it in another lambda, which is getting called inside the list comprehension expression:
Before:
>>> a = [(lambda x: x * i) for i in (1, 2)]
>>> a1
2
>>> a0
2
After:
>>> a = [(lambda y: (lambda x: y * x))(i) for i in (1, 2)]
>>> a1
2
>>> a0
1
(I had the outer lambda variable also = i, but I decided this is the clearer solution - I introduced y so that we can all see which witch is which).
Edit 2019-08-30:
Following a suggestion by @josoler, which is also present in an answer by @sheridp - the value of the list comprehension "loop variable" can be "embedded" inside an object - the key is for it to be accessed at the right time. The section "After" above does it by wrapping it in another lambda and calling it immediately with the current value of i. Another way (a little bit easier to read - it produces no 'WAT' effect) is to store the value of i inside a partial object, and have the "inner" (original) lambda take it as an argument (passed supplied by the partial object at the time of the call), i.e.:
After 2:
>>> from functools import partial
>>> a = [partial(lambda y, x: y * x, i) for i in (1, 2)]
>>> a0, a1
(2, 4)
Great, but there is still a little twist for you! Let's say we wan't to make it easier on the code reader, and pass the factor by name (as a keyword argument to partial). Let's do some renaming:
After 2.5:
>>> a = [partial(lambda coef, x: coef * x, coef=i) for i in (1, 2)]
>>> a0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() got multiple values for argument 'coef'
WAT?
>>> a[0]()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'x'
Wait... We're changing the number of arguments by 1, and going from "too many" to "too few"?
Well, it's not a real WAT, when we pass coef to partial in this way, it becomes a keyword argument, so it must come after the positional x argument, like so:
After 3:
>>> a = [partial(lambda x, coef: coef * x, coef=i) for i in (1, 2)]
>>> a0, a1
(2, 4)
I would prefer the last version over the nested lambda, but to each their own...
Edit 2020-08-18:
Thanks to commenter dasWesen, I found out that this stuff is covered in the Python documentation: https://docs.python.org/3.4/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result - it deals with loops instead of list comprehensions, but the idea is the same - global or nonlocal variable access in the lambda function. There's even a solution - using default argument values (like for any function):
>>> a = [lambda x, coef=i: coef * x for i in (1, 2)]
>>> a0, a1
(2, 4)
This way the coef value is bound to the value of i at the time of function definition (see James Powell's talk "Top To Down, Left To Right", which also explains why mutable default values are shunned).
Lambdas are just another way of defining a function
def foo(x):
return x + x
is the same as
foo = lambda x: x + x
So let's start with a function to do what you want:
def first_missing(items, base):
for number in itertools.count():
text = base + '_' + str(number)
if text not in items:
return text
The first thing to note is that you can't use loops inside a lambda. So we'll need to rewrite this without a loop. Instead, we'll use recursion:
def first_missing(items, base, number = 0):
text = base + '_' + str(number)
if text not in items:
return text
else:
return first_missing(items, base, number + 1)
Now, we also can't use an if/else block in a lambda. But we can use a ternary expression:
def first_missing(items, base, number = 0):
text = base + '_' + str(number)
return text if text not in items else first_missing(items, base, number + 1)
We can't have local variables in a lambda, so we'll use a trick, default arguments:
def first_missing(items, base, number = 0):
def inner(text = base + '_' + str(number)):
return text if text not in items else first_missing(items, base, number + 1)
return inner()
At this point we can rewrite inner as a lambda:
def first_missing(items, base, number = 0):
inner = lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1)
return inner()
We can combine two lines to get rid of the inner local variable:
def first_missing(items, base, number = 0):
return (lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1))()
And at long last, we can make the whole thing into a lambda:
first_missing = lambda: items, base, number = 0: (lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1))()
Hopefully that gives you some insight into what you can do. But don't ever do it because, as you can tell, lambdas can make your code really hard to read.
There's no need to use a lambda in this case, a simple for loop will do:
my_test = 'test_name_dup'
testlist = ['test_name', 'test_name_dup','test_name_dup_1', 'test_name_dup_3']
for i in xrange(1, len(testlist)):
if my_test + '_' + str(i) not in testlist:
break
print my_test + '_' + str(i)
> test_name_dup_2
If you really, really want to use a lambda for this problem, you'll also have to learn about itertools, iterators, filters, etc. I'm gonna build on thg435's answer, writing it in a more idiomatic fashion and explaining it:
import itertools as it
iterator = it.dropwhile(
lambda n: '{0}_{1}'.format(my_test, n) in testlist,
it.count(1))
print my_test + '_' + str(iterator.next())
> test_name_dup_2
The key to understanding the above solution lies in the dropwhile() procedure. It takes two parameters: a predicate and an iterable, and returns an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element.
For the iterable, I'm passing count(1), an iterator that produces an infinite number of integers starting from 1.
Then dropwhile() starts to consume the integers until the predicate is false; this is a good opportunity for passing an in-line defined function - and here's our lambda. It receives each generated integer in turn, checking to see if the string test_name_dup_# is present in the list.
When the predicate returns false, dropwhile() returns and we can retrieve the value that made it stop by calling next() on it.
You need to bind d for each function created. One way to do that is to pass it as a parameter with a default value:
lambda d=d: self.root.change_directory(d)
Now the d inside the function uses the parameter, even though it has the same name, and the default value for that is evaluated when the function is created. To help you see this:
lambda bound_d=d: self.root.change_directory(bound_d)
Remember how default values work, such as for mutable objects like lists and dicts, because you are binding an object.
This idiom of parameters with default values is common enough, but may fail if you introspect function parameters and determine what to do based on their presence. You can avoid the parameter with another closure:
(lambda d=d: lambda: self.root.change_directory(d))()
# or
(lambda d: lambda: self.root.change_directory(d))(d)
This is due to the point at which d is being bound. The lambda functions all point at the variable d rather than the current value of it, so when you update d in the next iteration, this update is seen across all your functions.
For a simpler example:
funcs = []
for x in [1,2,3]:
funcs.append(lambda: x)
for f in funcs:
print f()
# output:
3
3
3
You can get around this by adding an additional function, like so:
def makeFunc(x):
return lambda: x
funcs = []
for x in [1,2,3]:
funcs.append(makeFunc(x))
for f in funcs:
print f()
# output:
1
2
3
You can also fix the scoping inside the lambda expression
lambda bound_x=x: bound_x
However in general this is not good practice as you have changed the signature of your function.
f = range(20) f = filter(lambda n: n%2, f) f = filter(lambda n: n%3, f) print(list(f))
returns [1, 5, 7, 11, 13, 17, 19] as expected; However,
f = range(20)
for x in [2,3]:
f = filter(lambda n: n%x, f)
print(list(f))
returns [1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]
I'm not sure why the for loop doesn't do the exact same thing here. Any help would be appreciated!
Thanks!