|pekka niiranen||May 1, 2002 11:29 pm|
|Erik Max Francis||May 1, 2002 11:57 pm|
|Alex Martelli||May 2, 2002 2:03 am|
|Bengt Richter||May 2, 2002 9:21 am|
|Alex Martelli||May 2, 2002 10:00 am|
|Terry Reedy||May 2, 2002 11:11 am|
|Alex Martelli||May 2, 2002 12:25 pm|
|Bengt Richter||May 2, 2002 1:01 pm|
|holger krekel||May 2, 2002 1:17 pm|
|Steve Holden||May 2, 2002 1:18 pm|
|holger krekel||May 2, 2002 1:32 pm|
|Alex Martelli||May 2, 2002 2:05 pm|
|Bengt Richter||May 4, 2002 4:56 pm|
|Terry Reedy||May 4, 2002 10:38 pm|
|Alex Martelli||May 5, 2002 12:22 am|
|Paul Foley||May 5, 2002 10:11 pm|
|Lulu of the Lotus-Eaters||May 5, 2002 11:31 pm|
|Alex Martelli||May 6, 2002 12:10 am|
|Paul Foley||May 6, 2002 4:20 am|
|Alex Martelli||May 6, 2002 8:15 am|
|Paul Foley||May 6, 2002 6:34 pm|
|Steve Holden||May 7, 2002 5:25 am|
|Alex Martelli||May 7, 2002 7:00 am|
|Paul Foley||May 7, 2002 7:03 pm|
|Paul Foley||May 7, 2002 7:15 pm|
|Subject:||Theoretical question about Lambda|
|From:||Paul Foley (se...@below)|
|Date:||May 6, 2002 6:34:13 pm|
On Mon, 06 May 2002 15:15:59 GMT, Alex Martelli wrote:
Paul Foley wrote: ...
OK; question: what's the difference, if any, between
x = n do_something
def foo(x): do_something
as far as x is concerned?
Assuming these snippets are top-level code, "the difference as far as x is concerned" is clearly that x is a global name in the first snippet, and a local name of foo in the second snippet.
And if they're not at top level? The scope difference isn't really what I was getting at.
The point is that, in the case of something like
def foo(x): bar x = 7 baz
there's only _one_ binding for x: doing "x = 7" just changes the value in the preexisting binding. That's why
def foo(x): a = lambda: x x = 7 b = lambda: x return a,b
returns two functions that both return 7; if there was a new binding after the "x = 7", the functions would return different values [assuming you don't call foo(7), of course. Also assuming nested_scopes]
In Lisp, you can do both:
(defun foo (x &aux a b) (setq a (lambda () x)) (setq x 7) ; assignment (setq b (lambda () x)) (list a b))
(defun foo (x &aux a b) (setq a (lambda () x)) (let ((x 7)) ; binding (setq b (lambda () x))) (list a b))
(let ((a1 b1) (a2 b2)) ...)
is essentially syntactic sugar for
((lambda (a1 a2) ...) b1 b2)
Lambda is how you do binding; setq can only assign into an existing binding. Same with Python's "=", except that the compiler notices any assignments and automatically adds "&aux var" to the lambda list (to put it in Lisp terms) -- and /that's/ what does the binding, not the "=", which you can easily demonstrate:
def test(): print x x = 42
raises an error because the (empty, error-causing) binding for x is already in force when the "print" statement executes, before the "=" is even reached.
Given that (lambda: x) /does/ close over x with nested scopes enabled, can you explain why
fns = getfns(seq)
produces a list of functions that all return seq[-1]? And why, as you
Because "lambda: x" is a callable that returns whatever object name x is bound to at the time it's called (rather than, at the time it's created).
Yes, but it captures the binding that's in effect at the time the function is created (i.e., when the lambda form is evaluated, not when it's eventually called). That's what "closure" means.
And that's what I'm getting at: yes, when you call the function you get whatever value is in that binding at the time of the call -- the fact that all five functions return the same value shows that they all share the same binding!
def getfns2(seq): return [(lambda x=x: x) for x in seq]
produces functions that return all the elements of seq? [Assume you call them with no arguments!]
Because "lambda x=x: x" is a callable that (when called with no arguments) returns whatever object name x was bound to at the time the callable was created (rather than, at the time it's called).
Hmmm. Does it make a difference if I write (lambda q=x: q)? It still returns whatever value the variable (now named q) is bound to at the time of the call (/not/ when it was created!), but now you have a new binding, not shared by the other functions; the value in that new binding is the value of x at the time the binding was created [and you can't change it, in Python, but that's not relevant]
Of course, you could do
def getfns2(seq): return [(lambda x: lambda: x)(x) for x in seq]
to get the same effect without the unwanted optional argument. [Again, assuming nested_scopes is enabled]
What I'm saying is that when you explain Python to people by drawing boxes for variables with arrows pointing at their values, as in the recent thread, the binding is the box, or the box-and-arrow pair, not the arrow. Assignment is making an arrow point somewhere else; binding is making a new box, with its own arrow. [As long as you don't have dynamic variables, anyway; but Python doesn't]
-- Nonono, while we're making wild conjectures about the behavior of completely irrelevant tasks, we must not also make serious mistakes, or the data might suddenly become statistically valid. -- Erik Naggum (setq reply-to (concatenate 'string "Paul Foley " "<mycroft" '(#\@) "actrix.gen.nz>"))