Overcoming herpetophobia (or what's up w/ Python scopes)?

Paul Du Bois paul.dubois at gmail.com
Tue Jun 21 02:24:47 EDT 2005


kj wrote:
> I am hoping that it may be better this time around.  For one thing,
> like Perl, Python was then (and maybe still is) a "work in progress."
> So I figure that Python scoping may have improved since then.  Even
> if not, I think that Python is mature enough by now that adequate
> alternatives must have been devised for the Perlish features that
> I missed during my first attempt.

I don't know of any tutorials, but given that you're familiar with the
concept of closures and scopes I don't think you really need one to
understand what Python does and doesn't provide.

Python does allow you to refer to variables in lexically enclosing
scopes, and it closes over them properly.  Python (annoyingly) does
_not_ provide a way to write to the closed-over variable.  Assignments
always go into the local scope.  There is a "global" statement that
allows you to "target" the module scope; one can imagine an analagous
statement that allows you to target an intervening scope, but it
doesn't exist.

Some (incorrectly) interpret this to mean that the variable isn't
actually closed-over.  The following code executes without errors,
which shows that the closure really does refer to the outer variable,
and not some constant copy:

def closure_test():
    def make_closure():
        def closure():
            # a += 1  # this will give you an unbound local error at
runtime
            return a
        return closure
    fn = make_closure()

    a = 1
    assert fn() == a
    a = 2
    assert fn() == a

closure_test()

The canonical way around this is to add a layer of indirection -- isn't
that always the solution?

def closure_test2():
    def make_closure():
        def closure():
            a[0] += 1
            return a[0]
        return closure
    fn = make_closure()

    a = [1]
    assert fn() == 2
    assert fn() == 3
closure_test2()

p




More information about the Python-list mailing list