Need help with Python scoping rules

Terry Reedy tjreedy at
Wed Aug 26 19:52:36 CEST 2009

kj wrote:
> In <7figv3F2m3p0dU1 at> "Diez B. Roggisch" <deets at> writes:
>> Classes are not scopes.

Classes are objects.  In particular, they are (by default) instances of 
class 'type'. Unless 'scopes' were instances of some other metaclass, 
the statement has to be true. I understand 'scope' as referring to a 
section of code, as opposed to a runtime object.

Class statements introduce a new local namespace used to define the 
class.  Whether one considers that as introducing a new 'scope' depends, 
I suppose, on one's exact definition of scope.

> This looks to me like a major wart, on two counts.

It is a 'wart' that a Python object is not a 'scope', whatever that is 
to you? I have trouble comprehending that claim.

> First, one of the goals of OO is encapsulation, not only at the
> level of instances, but also at the level of classes.  Your comment
> suggests that Python does not fully support class-level encapsulation.

I really do not see how your claim follows from the comment. The irony 
of your 'two counts' is that the example of 'count 2' fails precisely 
because of the encapsulation that you claim does not exist as 'count 1'.

> Second, my example shows that Python puts some peculiar restrictions
> on recursion.

I claim it does not. Name-based recursion inherently requires that a 
function be able to access itself by name at the time it is called. This 
can be a bit tricky, especially in a language with dynamic rather than 
static name binding and resolution, as it requires that code within the 
function be able to access a scope outside itself in which the function 
name is defined. In other words, it requires that function code *not* be 
completely encapsulated. It also require that the appropriate name be 
used when there is one. Neither of these is a 'peculiar restriction' 
imposed by Python.

> class Demo(object):
>     def fact_rec(n):
>         if n < 2:
>             return 1
>         else:
>             return n * fact_rec(n - 1)

This function is just a function. It is not an instance method. It is 
not even a class method. It does not belong here and should not be here.

If you insist on putting it where it does not belong, then you have to 
call it by a name that works.  If you only call it after the class 
statement has finished, then 'Demo.fact_rec' works, as I believe someone 
else pointed out.

If you want to call the function during class creation, before (in this 
case) Demo exists, then binding it to a local name works. With 3.1

class Demo:
    def f1(n):
       if n < 2: return 1
       else:     return n * Demo.f1(n - 1)

    def f2(n,f):
       if n < 2: return 1
       else:     return n * f(n - 1, f)

    cvar = f2(5, f2)

print(Demo.f1(5), Demo.cvar, Demo.f2(5,Demo.f2))

# prints
120 120 120

> Recursive functions should be OK wherever functions are OK.

Iteration can and has been viewed as within-frame recursion. When 
iterative rather than recursive syntax is used, the naming issue is

> Is there any good reason (from the point of view of Python's overall
> design) for not fixing this?

After reading the above, what, if anything, do you think still needs to 
be fixed?

Before 2.2, Python functions were more encapsulated than they are today 
in that they could only access local and global namespaces but not outer 
function namespaces.  It would be possible to further de-encapsulate 
them by giving them direct access to lexically surrounding class 
namespaces, but this would increase the problem of name clashes without 
solving any real problems in proper Python code. It could also break the 
intentional design principle that function code should mean the same 
thing whether placed within or without a class statement. This principle 
allows functions to be added to existing classes as attributes and work 
as methods that same as if they had been defined with the class.

Terry Jan Reedy

More information about the Python-list mailing list