Skip to content

Latest commit

 

History

History
140 lines (110 loc) · 5.2 KB

name-binding.md

File metadata and controls

140 lines (110 loc) · 5.2 KB

Python Names, Binding and Namespaces

Namespaces are one honking great idea -- let's do more of those!
--The Zen of Python ("import this")

The primary documentation for this is the Execution model section of the Python 3 reference and the Scopes and Namespaces section of the Classes tutorial. Wikipedia also has a useful summary. How lookup works gets into the deep, grungy details.

Python programs are constructed from code blocks: modules, function bodies, and class definitions. Blocks are executed as a unit and each block has its own namespace, a map of name → value bindings accessible as attributes on the object where one exists (modules, classes and class instances, but not stand-alone functions). In CPython the namespace is stored as the __dict__ attribute on the object but this is probably implementation-dependent.

There are four categories of namespace that are searched in 'LEGB' order to find the nearest in-scope binding:

  1. (L) The local namespace of currently executing function or class definition.
  2. (E) The namespaces of lexically enclosing functions or class definitions. locals() returns the current function or class's namespace dictionary.
  3. (G) The namespace of the current module, refered to as a 'Global' namespace. (Despite the name, it's a namespace local to just that module.) globals() returns the current module object's namespace dictionary. (Use sys.modules[__name__] to get the module itself. It has an attribute __dict__, which symbol is not in the global namespace, containing the global namespace.)
  4. (B) The namespace of the builtins module. This is the outermost scope and is accessible from everywhere. The CPython implementation also makes this available via the __builtins__ global set in every module namespace.

Two namespaces are created when the interpreter starts: the builtin namespace on the builtin module and a 'global' namespace on the __main__ module in which the top-level code runs. (Well, typically more will be created for other modules that are loaded at startup time.)

Binding

Bindings are created with any of the following statements:

  1. Assignment: x = ....
  2. global x and nonlocal x, which bind x to an enclosing block's x and the current module's x, respectively. In both cases you may change the binding and that will be reflected in the encloser's binding.
  3. Various forms of the import statement.
  4. def x():
  5. class x:

These all create a binding that applies to the entire block, both before and after the statement creating the binding, though the variable will be unbound before the statement that creates the binding. Thus,

x = 1
def f():
    print('x=%s' % x)
    x = 3
f()

⇒ UnboundLocalError: local variable 'x' referenced before assignment

Classes

Class definitions are executed to build the class; they have their own namespace (for class variables, including functions) while executing and the bindings become available as attributes on the class object. Instance variables are referenced explicitly as attributes the first (self) parameter passed to instance functions.

class C:
    c = 1
    @staticmethod
    def s(cls): pass
    def f(self):
        self.i = 2

o = C()
C.c                 # class variable        ==> 1
C.s                 # class method          ==> <function __main__.C.s>
C.f                 # instance method       ==> <function __main__.C.f>
o.f(); o.i          # instance variable     ==> 2

Inheritance

Define base classes for inheritance using an argument list after the class name. Each argument must evaluate to a class object. When a requested attribute is not found in the class itself, each base class is searched in turn.

from collections.abc import *
class C(Sized, Iterator):
    def __len__(self):  # Abstract from Sized; must be implemented.
        return 0
    def __next__(self): # Abstract from Iterator; must be implemented.
        raise StopIteration()

c = C()
isinstance(Sized, c)        # ⇒ True
isinstance(Iterator, c)     # ⇒ True
iter(c)                     # Calls  __iter__() provided by Iterator

Metaclasses

See Metaclasses.

Exception Hierarchy

+-object
  +-Exception
    +-BaseException
      +-NameError
        +-UnboundLocalError