|
| 1 | +PEP: 840 |
| 2 | +Title: Name Resolution in Class Namespaces |
| 3 | +Author: Jeremy Hylton <jeremy@python.org>, |
| 4 | + Guido van Rossum <guido@python.org> |
| 5 | +Discussions-To: https://discuss.python.org/t/pep-840-name-resolution-in-class-namespaces/108166 |
| 6 | +Status: Draft |
| 7 | +Type: Standards Track |
| 8 | +Created: 15-Jul-2026 |
| 9 | +Python-Version: 3.16 |
| 10 | +Post-History: `16-Jul-2026 <https://discuss.python.org/t/pep-840-name-resolution-in-class-namespaces/108166>`__ |
| 11 | + |
| 12 | + |
| 13 | +Abstract |
| 14 | +======== |
| 15 | + |
| 16 | +There is a long-standing inconsistency in the way variable names are |
| 17 | +resolved in classes. Several alternatives to resolve this |
| 18 | +inconsistency are discussed. |
| 19 | + |
| 20 | +Movtivation |
| 21 | +=========== |
| 22 | + |
| 23 | +Name resolution in a class namespace uses a partial dynamic lookup. A |
| 24 | +name can be either local or global depending on whether an assignment |
| 25 | +to the name has occured during the exection of the class body. If a |
| 26 | +name is used before assignment, it will be looked up in globals (and |
| 27 | +builtins). |
| 28 | + |
| 29 | +If a class is defined within a function scope, a name may be resolved |
| 30 | +to the nearest enclosing scope. If name local to an enclosing scope, |
| 31 | +but the name is not bound, a NameError will occur. |
| 32 | + |
| 33 | +The apparent consistency problem is that names may be both local and |
| 34 | +global in the same class block, but they cannot be both local and |
| 35 | +free. Or, name resolution behaves differently in a class depending on |
| 36 | +whether it is defined at the top-level or inside another block. If a |
| 37 | +global variable exists, it can be used to resolve a free variable |
| 38 | +unless that variable is bound in an enclosing scope of the class. |
| 39 | + |
| 40 | +Here is an example of resolution of a free variable in a class: |
| 41 | + |
| 42 | +>>> x = 0 |
| 43 | +>>> def f(x): |
| 44 | +... class A: |
| 45 | +... a = x |
| 46 | +... return A |
| 47 | +... |
| 48 | +>>> A = f(1) |
| 49 | +>>> A.a # the value of the parameter x, not the global x |
| 50 | +1 |
| 51 | + |
| 52 | +The variable x is resolved to the parameter of the function x. The |
| 53 | +global is ignored. This behavior is the standard name resolution |
| 54 | +defined in :pep:`227` and :pep:`3104`. |
| 55 | + |
| 56 | +If x is used as a local variable, the behavior is different at the |
| 57 | +top-level and inside another block. If the same code also uses x as a |
| 58 | +local variable, then the initial reference to x is resolved |
| 59 | +differently. |
| 60 | + |
| 61 | +>>> x = 0 |
| 62 | +>>> def f(x): |
| 63 | +... class A: |
| 64 | +... a = x |
| 65 | +... x = 42 |
| 66 | +... return A |
| 67 | +... |
| 68 | +>>> A = f(1) |
| 69 | +>>> A.a # the value of the global x, not the parameter x |
| 70 | +0 |
| 71 | + |
| 72 | +The first reference to x is no longer bound to the local variable x |
| 73 | +defined in f, but instead uses the global variable. |
| 74 | + |
| 75 | +The set of namespaces consulted are determined lexically, but it |
| 76 | +cannot be determined statically whether a particular reference will be |
| 77 | +resolved using the global namespace. |
| 78 | + |
| 79 | +>>> x = 0 |
| 80 | +>>> def f(var): |
| 81 | +... class A: |
| 82 | +... x = 10 |
| 83 | +... if var in locals(): |
| 84 | +... del locals()[var] |
| 85 | +... a = x |
| 86 | +... return A |
| 87 | +... |
| 88 | +>>> A1 = f("x") |
| 89 | +>>> A2 = f("y") |
| 90 | +>>> A1.a, A2.a |
| 91 | +(0, 10) |
| 92 | + |
| 93 | + |
| 94 | +Background |
| 95 | +========== |
| 96 | + |
| 97 | +The Python 2.0 definition specifies exactly three namespaces to |
| 98 | +check for each name -- the local namespace, the global namespace, |
| 99 | +and the builtin namespace. Starting with Python 2.1, lexical scoping |
| 100 | +was used and free variables could be resolved to a binding in an |
| 101 | +enclosing scope. Class namespaces were a special case, and free variables |
| 102 | +were not resolved in enclosing scopes. They used special LOAD_NAME / |
| 103 | +STORE_NAME opcodes that explicit checked local and global namespaces. |
| 104 | + |
| 105 | +In Python 3.4, free variables in classes were resolved in enclosing scopes, |
| 106 | +but a local variable used before assignment was still resolved in the global |
| 107 | +scope. The language specification was not updated at this time, so it |
| 108 | +still specifies the pre-3.4 behavior: |
| 109 | + |
| 110 | + A class definition is an executable statement that may use and define names. |
| 111 | + These references follow the normal rules for name resolution with an exception |
| 112 | + that unbound local variables are looked up in the global namespace. |
| 113 | + |
| 114 | +Class namespaces and top-level module namespaces both use LOAD_NAME / STORE_NAME |
| 115 | +opcodes that reflect the early local / global / builtin scoping rules. Class |
| 116 | +namespaces are also special, because the class namespace become the attributes |
| 117 | +of the class object. Given these differences, the different scoping rules for |
| 118 | +classes weren't considered when :pep:`227` was written. |
| 119 | + |
| 120 | +A bug was filed in 2002. The PEP author closed the bug with the |
| 121 | +comment, "Just don't write code that abuses the wart." |
| 122 | +https://github.com/python/cpython/issues/36300 |
| 123 | +Another bug was filed in 2010, leading the same author to suggest a change. |
| 124 | +https://github.com/python/cpython/issues/53472 |
| 125 | +Apparently, inconsistent behavior in namespaces can lead to |
| 126 | +inconsistent responses to identical bugs. |
| 127 | + |
| 128 | +Proposal |
| 129 | +======== |
| 130 | + |
| 131 | +There are several alternatives we could choose among. A few simple |
| 132 | +alternatives seem wrong. We could revert to pre-3.4 behavior, but it |
| 133 | +was surprising the free variables did not work in class scopes. We |
| 134 | +could keep the current behavior, but it is seems inconsistent. |
| 135 | + |
| 136 | +One approach is to make class namespaces work more like function |
| 137 | +namespaces. If a local variable is used at a time when it is not |
| 138 | +bound, it raises a NameError. This rule is simple and consistent. The |
| 139 | +primary drawback of this approach is that it will break code. Code |
| 140 | +that depends on this feature is inscrutable, depending on the reader |
| 141 | +to understand whether the local or global reference was |
| 142 | +intended. Inscrutable, though, is not the same as undefined or broken |
| 143 | + |
| 144 | +Another approach is to change the behavior of free variable |
| 145 | +resolution to use the global namespaces when a name is unbound. If |
| 146 | +current code would raise a NameError, because a variable was unbound |
| 147 | +in the enclosing scope, it would be resolved in the global namespace. |
| 148 | + |
| 149 | +There is a third approach that is a subtle variant of the second. If |
| 150 | +a local variable is unbound, and that variable has a binding in an |
| 151 | +enclosing scope, use that namespace rather than the global namespace. |
| 152 | + |
| 153 | +>>> x = 0 |
| 154 | +>>> def f(): |
| 155 | +... x = 1 |
| 156 | +... class A: |
| 157 | +... x = 2 |
| 158 | +... del x |
| 159 | +... a = x # Should this use f's local or global? |
| 160 | +... return A |
| 161 | +... |
| 162 | +>>> A = f() |
| 163 | +>>> A.a |
| 164 | +? |
| 165 | + |
| 166 | +If a local variable is unbound and it can be resolved in another |
| 167 | +namespace anyway, why only the global namespace? Why not use the |
| 168 | +full set of standard name resolution rules? |
| 169 | + |
| 170 | +This option seems most consistent, but makes the implementation more |
| 171 | +complicated. It can't be statically determinted whether a variable is |
| 172 | +bound at a particular point, so we would need to allocate a cell for |
| 173 | +any local variable of the class that shadows a local variable in an |
| 174 | +enclosing scope. Since dynamic manipulation of local variables is |
| 175 | +unusual, we would expect the extra closures required to almost always |
| 176 | +be unused. It would nonetheless be a somewhat unusual case-- a nested |
| 177 | +class definition that has a local variable that shadows a local |
| 178 | +variable in an enclosing scope. |
| 179 | + |
| 180 | + |
| 181 | +Copyright |
| 182 | +========= |
| 183 | + |
| 184 | +This document is placed in the public domain or under the |
| 185 | +CC0-1.0-Universal license, whichever is more permissive. |
0 commit comments