News for hackers. Stuff that matters.
Re:WTFPython – Understanding Python through surprising snippets by Kwantuum on Monday December 23, 2019 @05:20AM (#21862683)
You can achieve the same thing in python by using two lambdas (which is actually what you're doing in JS with map):

   >>> powers_of_x = [(lambda i: (lambda x: x**i))(i) for i in range(10)]
   >>> [f(2) for f in powers_of_x]
   [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Or you can use default parameter values to use a single lambda (though this means it can be overridden, it's not semantically equivalent to the js implementation)

   >>> powers_of_x = [lambda x, i=i: x**i for i in range(10)]
   >>> [f(2) for f in powers_of_x]
   [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
your python snippet is equivalent to the following JS:

   >>> function* comprehension(iterable){
   >>>   let i;
   >>>   for(let j of iterable){
   >>>     i = j;
   >>>     yield x => x**i;
   >>>   }
   >>> }
   >>> powersOfX = [...comprehension([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])];
   >>> powersOfX.map(f => f(2))
   [512, 512, 512, 512, 512, 512, 512, 512, 512, 512]
And Python's comprehensions are actually a shorthand for writing the above generator with this syntax: yieldExpression for i in iterable. The semantics are consistent with the regular for..in

   >>> def comprehension(iterable):
   >>>     for i in iterable:
   >>>         yield lambda x: x**i
   >>> [*comprehension(range(10))]
is equivalent to

   >>> [lambda x: x**i for i in range(10)]
This is all a consequence of python's late binding.
Re:WTFPython – Understanding Python through surprising snippets by Izkata on Monday December 23, 2019 @08:04AM (#21863340)
Amusingly, the "default parameter" version relies on a feature that also gives rise to another WTPython entry: https://github.com/satwikkansal/wtfpython/blob/master/README...
Re:WTFPython – Understanding Python through surprising snippets by sjagoe on Monday December 23, 2019 @08:36AM (#21863483)
That's a different issue around default arguments that are mutable, rather than default arguments generally.

The lambda case here is more like a default argument of a constant integer (immutable) than a default that is a list, which can be altered directly by the function it's a default of.

Re:WTFPython – Understanding Python through surprising snippets by Izkata on Monday December 23, 2019 @08:47AM (#21863532)
The underlying feature that both rely on is that default arguments are set on function declaration instead of function call. Mutable/immutable only affects whether or not you hit the bug.
Re:WTFPython – Understanding Python through surprising snippets by mplanchard on Monday December 23, 2019 @09:14AM (#21863684)
Parenthetical comprehensions (generator expressions) are equivalent to your expanded function, but list comprehensions are not. `(x for x in range(10))` creates a generator, but using square brackets converts it to a list, including allocating the necessary memory. If you’re trying to do yield and streaming, the parens will serve you better.
Re:WTFPython – Understanding Python through surprising snippets by Kwantuum on Monday December 23, 2019 @03:47PM (#21867219)
You will notice that I explicitly unpacked the generator object in the brackets below the generator function by prefixing it with an asterisk.