Need help with Python scoping rules

Diez B. Roggisch deets at nospam.web.de
Tue Aug 25 12:14:26 EDT 2009


kj wrote:

> 
> 
> 
> I have many years of programming experience, and a few languages,
> under my belt, but still Python scoping rules remain mysterious to
> me.  (In fact, Python's scoping behavior is the main reason I gave
> up several earlier attempts to learn Python.)
> 
> Here's a toy example illustrating what I mean.  It's a simplification
> of a real-life coding situation, in which I need to initialize a
> "private" class variable by using a recursive helper function.
> 
> class Demo(object):
>     def fact(n):
>         if n < 2:
>             return 1
>         else:
>             return n * fact(n - 1)
> 
>     _classvar = fact(5)
> 
> This code fails to compile, with the error "global name 'fact' not
> defined".
> 
> Scanning the Python Language Reference page I see nothing that
> would suggest to me a discussion of Python's scoping rules, let
> alone anything that would help me solve the specific problem above.
> I'm sure it's in there, *somewhere*, but it's anyone's guess where.
> 
> Likewise, my book, Beazley's "Python: Essential Reference" is of
> no help.  I don't doubt that the answer to my question "is in there,
> *somewhere*", but finding it (without reading the book sequentially
> from page 1) is a tall order.
> 
> All that's left is trial-and-error, the worst kind of programming.
> And still I can't find the right way to do this...  I've tried
> every variant of this code that I can imagine, including decorating
> fact with @staticmethod or @classmethod, etc., etc.  (In the latter
> case, I get cryptic errors saying that the staticmethod or classmethod
> object is not callable.  Or something like that.)

Classes are not scopes. 

So the above doesn't work because name resolution inside functions/methods
looks for local variables first, then for the *global* scope. There is no
class-scope-lookup.

If you want anything else, you need to qualify it with a full name,
Demo.fact. Which isn't working for your example because "Demo" isn't
available yet.

But if you insist on the above methodology, you can do this:


class Demo(object):

    def fact(n):
        def inner(n):
            if n < 2:
                return 1
            else:
                return n * inner(n - 1)
        return inner(n)

    _classvar = fact(5)

This makes inner a *local* variable, which is found.

Diez




More information about the Python-list mailing list