15

I'm trying to perform some analysis of scope in Python 3 source code and I'm stuck with how the nonlocal statement statement works inside a class definition.

As I understand it, the class definition executes its body inside a new namespace (call it dict) and binds the class name to the result of type(name, bases, dict). Nonlocal x should work as long as it refers to a variable that is bound somewhere in the enclosing non-local scope.

From this I expect the following code to compile and run:

class A:
    v = 1
    class B:
        nonlocal v
        v = 2

but this fails with

SyntaxError: no binding for nonlocal 'v' found

while the following code runs perfectly

def A():
    v = 1
    class B:
        nonlocal v
        v = 2

Can anyone explain the difference here between the closure of the function definition and the class definition?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Andyrooger
  • 6,748
  • 1
  • 43
  • 44
  • More research - in the last code sample, locals() in A is {v:1}, whereas inside B it is {v:2, '`__module__`':'`__main__`', '`__locals__`':{...}} – Andyrooger Mar 29 '11 at 00:42
  • This follows directly from the scoping rules; `class` doesn't create a scope, so it can't create an enclosing scope, so it can't create an enclosing scope that is subsequently accessed via `nonlocal`. – Karl Knechtel Sep 10 '22 at 09:25

2 Answers2

13

Lexical scoping applies only to function namespaces, otherwise methods defined inside a class would be able to "see" the class level attributes (which is by design - those attributes must instead be accessed as attributes of self inside the method).

The same limitations that cause the class level variables to be skipped over by references from methods also keep the nonlocal keyword from working its magic. (global does work though, since that doesn't rely on the lexical scoping machinery)

ncoghlan
  • 40,168
  • 10
  • 71
  • 80
  • Thanks, this makes sense. I had assumed there was some very basic form of stack that would work the same for every level. Noticing the symtable module docs changed my mind but I didn't really understand what was going on or why until your answer. – Andyrooger Mar 29 '11 at 01:50
5

Python handles class and function definitions rather differently. For example, your A.v is not a variable of A but rather an attribute of it. The namespace created by a class is not, therefore, a scope. I am not surprised that nonlocal does not work as you're trying to use it.

kindall
  • 178,883
  • 35
  • 278
  • 309
  • Thanks for the reply. So the function scope is created when it is run rather than when it's defined. As the body of the class definition is, I assume, executed immediately in a different namespace, does this not create a scope just for the duration of this execution? - I'm wondering if this is happening for the same reason an inner class can't access the attributes of an outer class... – Andyrooger Mar 29 '11 at 01:00
  • 1
    It does create a temporary scope, but it's a different *kind* of scope. The compiler uses different rules in deciding which attributes are visible (both for reference from inner scopes and for writing to outer scopes). – ncoghlan Mar 29 '11 at 01:43