An Introduction to Programming for Bioscientists: A Python-Based Primer
Fig 2
Python’s scope hierarchy and variable name resolution.
As described in the text, multiple names (variables) can reference a single object. Conversely, can a single variable, say x, reference multiple objects in a unique and well-defined manner? Exactly this is enabled by the concept of a namespace, which can be viewed as the set of all ↔
mappings for all variable names and objects at a particular “level” in a program. This is a crucial concept, as everything in Python is an object. The key idea is that
↔
mappings are insulated from one another, and therefore free to vary, at different “levels” in a program—e.g., x might refer to object obj2 in a block of code buried (many indentation levels deep) within a program, whereas the same variable name x may reference an entirely different object, obj1, when it appears as a top-level (module-level) name definition. This seeming ambiguity is resolved by the notion of variable scope. The term scope refers to the level in the namespace hierarchy that is searched for
↔
mappings; different mappings can exist in different scopes, thus avoiding potential name collisions. At a specific point in a block of code, in what order does Python search the namespace levels? (And, which of the potentially multiple
↔
mappings takes precedence?) Python resolves variable names by traversing scope in the order
→
→
→
, as shown here.
stands for the local, innermost scope, which contains local names and is searched first;
follows, and is the scope of any enclosing functions; next is
, which is the namespace of all global names in the currently loaded modules; finally, the outermost scope
, which consists of Python’s built-in names (e.g., int), is searched last. The two code examples in this figure demonstrate variable name resolution at local and global scope levels. In the code on the right-hand side, the variable e is used both (i) as a name imported from the
module (global scope) and (ii) as a name that is local to a function body, albeit with the global keyword prior to being assigned to the integer -1234. This construct leads to a confusing flow of logic (colored arrows), and is considered poor programming practice.