Today's article in our series of articles about Python internals' will discuss naming, which is the ability to bind names to an object, like we can see in the statement a = 1 (in other words, this article is roughly about what many languages call variables). Naturally, naming is central to Python's behaviour and understanding both its semantics and mechanics are important precursors to our quickly approaching discussions of code evaluation, code objects and stack frames. That said, it is also a delicate subject because anyone with some programming experience knows something about it, at least instinctively (you've done something like a = 1 before, now haven't you?). This rarely-formally-learned familiarity laden with language-specific nuances might lead to false assumptions and gut-feeling-led vagueness, and while Python aims not to surprise, some subtle details which you weren't aware of might turn out to be surprising nonetheless. So to solidify our foundations, we'll begin with some formality and terminology.

When we evaluate a = b = c = [] , we create one list and give it three different names. In formal terms, we'd say that the newly instantiated list object is now bound to three identifiers that refer to it (I also saw and liked the word referent used for the now-referred-to object in the weakref module's documentation). This distinction between names and the objects bound to them is important. If we evaluate a.append(1) , we will see that b and c are also affected; we didn't mutate a , we mutated its referent, so the mutation is uniformly visible via any name the object was referred to. On the other hand, if we will now do a b = [] , a and c will not change, since we didn't actually change the object which b referred to but rather did a re-binding of the name b to a (newly created and empty) list object. Also recall that binding is one of the ways to increase the referent's reference count, this is worthy of noting even though reference counting isn't our subject at the moment.

A name binding is commonly created by use of the assignment statement, which is a statement that has an 'equals' symbol ( = ) in the middle, "stuff to assign to" or targets on the left, and "stuff to be assigned" (an expression) on the right. A target can be a name (more formally called an identifier) or a more complex construct, like a sequence of names, an attribute reference ( primary_name.attribute ) or a subscript ( primary_name[subscript] ). The highly recommended formal definition of assignment is here, what I present here is a coarse simplification aimed to suit our bare minimum needs for the article. Name binding is undone with the deletion statement del , which is roughly " del followed by comma-separated targets to unbind" (formal specification here). Naturally, much like binding a name to an object increases that object's reference count, so does deletion decrease it. Finally, note that name binding can be done without an assignment as bindings are also created by def , class , import (and others), this is also of less importance to us now.

Scope is a term relating to the visibility of an identifier throughout a block, or a piece of Python code executed as a unit: a module, a function body and a class definition are blocks (control-blocks like those of if and while are not code blocks in Python). A namespace is an abstract environment where the mapping between names and the objects they refer to is made (incidentally, in current CPython, this is indeed implemented with the dict mapping type). The rules of scoping determine in which namespace will a name be sought after when it is used, or rather resolved. You probably know instinctively that a name bound in function foo isn't visible in an unrelated function bar , this is because by default names created in a function will be stored in a namespace that will not be looked at when name resolution happens in another, unrelated function. Scope determines not just when a name will be visible as it is resolved or 'read' (i.e., if you do spam = eggs , where will eggs come from) but also as it is bound or 'written' (i.e., in the same example, where will spam go to). When a namespace will no longer be used (for example, the private namespace of a function which returns) all the names in it are unbound (this triggers reference count decrease and possibly deallocation, but this doesn't concern us now).

Scoping rules change based on the lexical context in which code is compiled. For example, in simpler terms, code compiled as a plain function's body will resolve names slightly differently when evaluated when compared with code compiled as part of a module's initialization code (the module top-level code). Special statements like global and nonlocal exist and can be applied to names thus that resolution rules