On Mon, 24 Mar 2003 03:42:06 +0900
Paul Prescod <paul / prescod.net> wrote:

> Joel VanderWerf wrote:
> > ...
> > 
> > But in Python, the inner function only has access to the _object_, not 
> > to the original variable which refers to the object, and so you have to 
> > "box" the value inside an object if you want to have shared references. 
> 
> No, you still don't undestand the issue properly. You're getting closer, 
> but not quite there yet.
> 
> y = 0
> 
> def foo():
>      global y
>      x = 0
>      def bar():
>          print x, y
>      bar()
>      x = y = 1
>      bar()
>      x = y = 2
>      bar()
>      x = y = 3
>      bar()
>      x = y = 4
>      bar()
>      x = y = 5
> 
> foo()
> 
> 0 0
> 1 1
> 2 2
> 3 3
> 4 4
> 
> Now just as in Ruby, 0, 1, 2, 3, 4 are separate objects. It is literally 
> impossible to change their values. All you can do is change bindings TO 
> the variables. So obviously "bar" is really inheriting the _bindings_ 
> for x and y because it is the _bindings_ that are changing.
> 
> So what's the problem? Consider this program:
> 
> y = 0
> 
> def foo():
>      x = 0
>      def bar():
>          print x, y
>      def change(z):
>          global y
>          x = y = z
> 
>      change(1)
>      bar()
>      change(2)
>      bar()
>      change(3)
>      bar()
>      change(4)
>      bar()
> 
> foo()
> 
> The output is:
> 
> 0 1
> 0 2
> 0 3
> 0 4
> 
> This is because Python has always adopted the rule that if you assign to 
> a local variable it springs into existence -- as a local. If you want to 
> overwrite a global variable, you have to specifically say: "please 
> overwrite this global." It prevents people from accidentally overwriting 
> globals with locals.
> 
> But there is no syntax for saying: "please overwrite this intermediate 
> closure variable." It would be as easy as adding a keyword 
> "intermediate" or "closure". It's purely a syntactic issue.
> 
> _But_ the addition would be useless in practice because this problem 
> almost never arises in real code. Its only purpose would be to answer 
> Lisp and Ruby advocates who want to say that Python doesn't really have 
> closures. I don't know whether Guido will ever add it for, er, closure, 
> but I do know that I have _never_ _once_ needed this keyword in hundreds 
> of thousands of lines of real Python code I have written. And I am thus 
> going to fight my temptation to go and bug Guido to do it so that we can 
> put an end to permathreads about Python's lack of closures. ;) If this 
> problem ever arose in my code (which it has not) then I could work 
> around it thus:
> 
> y = 0
> 
> def foo():
>      x = [0]
>      def bar():
>          print x[0], y
>      def change(z):
>          global y
>          x[0] = y = z
> 
>      change(1)
>      bar()
>      change(2)
>      bar()
>      change(3)
>      bar()
>      change(4)
>      bar()
> 
> foo()
> 
> 1 1
> 2 2
> 3 3
> 4 4
> 
> This should prove that the problem is really not deep in the Python 
> interpreter or anything like that. It would be a half day's work to 
> write the patch that added the "intermediate" keyword.
> 
> By the way, there was a time when Python really did lack closures but 
> there was a hacky workaround. This is where the idea that Python did not 
> have "real" closures became popular (because it was true). Then Python 
> added closures, but left out one minor feature and the minor feature 
> allowed the idea to persist even when it had ceased to be true.

This is true.  Some distros still ship an older version of Python without the closures feature.  I don't think anyone really cares about the more esoteric issue described here.

> 
>   Paul Prescod
> 
> 
>