Path: csiph.com!news.swapon.de!eternal-september.org!feeder.eternal-september.org!mx02.eternal-september.org!.POSTED!not-for-mail From: Nobody Newsgroups: comp.lang.python Subject: Re: What does a list comprehension do (was: Late-binding of function defaults (was Re: What is a function parameter =[] for?)) Date: Thu, 26 Nov 2015 11:13:44 +0000 Organization: A noiseless patient Spider Lines: 77 Message-ID: References: <877fldnm9z.fsf@handshake.de> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Injection-Info: mx02.eternal-september.org; posting-host="152d4dee6f95183c956ee6fa63d7e69f"; logging-data="12935"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+vKZlI8eIRSwpD7xqIpdeX" User-Agent: Pan/0.14.2 (This is not a psychotic episode. It's a cleansing moment of clarity.) Cancel-Lock: sha1:t/V2x9dO6KmFzDoAoUODZRwM66k= Xref: csiph.com comp.lang.python:99555 On Wed, 25 Nov 2015 14:51:23 +0100, Antoon Pardon wrote: > Am I missing something? The issue is with lambdas rather than with list comprehensions per se. Python's lambdas capture free variables by reference, not value. > x = 3 > f = lambda y: x + y > f(0) 3 > x = 7 > f(0) 7 The same issue applies to nested functions: > def foo(): = x = 3 = def f(y): = return x + y = print f(0) = x = 7 = print f(0) = > foo() 3 7 And also to non-nested functions (but most people expect that): > x = 3 > def f(y,x=x): = return x + y = > print f(0) 3 > x=7 > print f(0) 3 If you want to capture a variable by value, add a parameter with a default value using that variable: > def foo(): = x = 3 = def f(y, x=x): = return x + y = print f(0) = x = 7 = print f(0) = > foo() 3 3 This also works for lambdas: > x = 3 > f = lambda y,x=x: x + y > f(0) 3 > x = 7 > f(0) 3 Returning to the original expression: > q = [lambda x: i * x for i in range(4)] > q[0](1), q[3](1) (3, 3) > q = [lambda x,i=i: i * x for i in range(4)] > q[0](1), q[3](1) (0, 3)