A Python program accesses data values through references. A reference is a name that refers to a value (object).
A Python program accesses data values through references. A reference is a "name" that refers to a value (object). References take the form of variables, attributes, and items. In Python, a variable or other reference has no intrinsic type. The object to which a reference is bound at a given time always has a type, but a given reference may be bound to objects of various types in the course of the program’s execution.
In Python, there are no "declarations." The existence of a variable begins with a statement that binds the variable (in other words, sets a name to hold a reference to some object). You can also unbind a variable, resetting the name so it no longer holds a reference. Assignment statements are the most common way to bind variables and other references. The del statement unbinds references.
Binding a reference that was already bound is also known as rebinding it. Whenever we mention binding, we implicitly include rebinding (except where we explicitly exclude it). Rebinding or unbinding a reference has no effect on the object to which the reference was bound, except that an object goes away when nothing refers to it. The cleanup of objects with no references is known as garbage collection.
You can name a variable with any identifier except the 30-plus reserved as Python’s keywords. A variable can be global or local. A global variable is an attribute of a module object. A local variable lives in a function’s local namespace.
The main distinction between the attributes and items of an object is in the syntax you use to access them. To denote an attribute of an object, use a reference to the object, followed by a period (.), followed by an identifier known as the attribute name. For example, x.y refers to one of the attributes of the object bound to name x, specifically that attribute whose name is 'y'.
To denote an item of an object, use a reference to the object, followed by an expression within brackets ([]). The expression in brackets is known as the item’s index or key, and the object is known as the item’s container. For example, x[y] refers to the item at the key or index bound to name y, within the container object bound to name x.
Attributes that are callable are also known as methods. Python draws no strong distinctions between callable and noncallable attributes, as some other languages do. All rules about attributes also apply to callable attributes (methods).
A common programming error is trying to access a reference that does not exist. For example, a variable may be unbound, or an attribute name or item index may not be valid for the object to which you apply it. The Python compiler, when it analyzes and compiles source code, diagnoses only syntax errors. Compilation does not diagnose semantic errors, such as trying to access an unbound attribute, item, or variable. Python diagnoses semantic errors only when the errant code executes — that is, at runtime. When an operation is a Python semantic error, attempting it raises an exception. Accessing a nonexistent variable, attribute, or item — just like any other semantic error — raises an exception.
Assignment statements can be plain or augmented. Plain assignment to a variable (e.g., name=value) is how you create a new variable or rebind an existing variable to a new value. Plain assignment to an object attribute (e.g., x.attr=value) is a request to object x to create or rebind attribute 'attr'. Plain assignment to an item in a container (e.g., x[k]=value) is a request to container x to create or rebind the item with index or key k.
Augmented assignment (e.g., name+=value) cannot, per se, create new references. Augmented assignment can rebind a variable, ask an object to rebind one of its existing attributes or items, or request the target object to modify itself. When you make a request to an object, it is up to the object to decide whether and how to honor the request, and whether to raise an exception.
A plain assignment statement in the simplest form has the syntax:
target = expression
The target is known as the lefthand side (LHS), and the expression is the righthand side (RHS). When the assignment executes, Python evaluates the RHS expression, then binds the expression’s value to the LHS target. The binding does not depend on the type of the value. In particular, Python draws no strong distinction between callable and noncallable objects, as some other languages do, so you can bind functions, methods, types, and other callables to variables, just as you can numbers, strings, lists, and so on. This is part of functions and the like being first-class objects.
Details of the binding do depend on the kind of target. The target in an assignment may be an identifier, an attribute reference, an indexing, or a slicing:
An identier
Is a variable name. Assigning to an identifier binds the variable with this name.
An attribute reference
Has the syntax obj.name, where obj is an arbitrary expression, and name is an identifier, known as an attribute name of the object. Assigning to an attribute reference asks object obj to bind its attribute named 'name'.
An indexing
Has the syntax obj[expr]. obj and expr are arbitrary expressions. Assigning to an indexing asks container obj to bind its item indicated by the value of expr, also known as the index or key of the item in the container.
A slicing
Has the syntax obj[start:stop] or obj[start:stop:stride]. obj, start, stop, and stride are arbitrary expressions. start, stop, and stride are all optional (i.e., obj[:stop:] and obj[:stop] are also syntactically correct slicings, equivalent to obj[None:stop:None]). Assigning to a slicing asks container obj to bind or unbind some of its items. Assigning to a slicing such as obj[start:stop:stride] is equivalent to assigning to the indexing obj[slice(start, stop, stride)], whose instances represent slices.
We’ll get back to indexing and slicing targets when we discuss operations on lists and on dictionaries in the later chapter.
When the target of the assignment is an identifier, the assignment statement specifies the binding of a variable. This is never disallowed: when you request it, it takes place. In all other cases, the assignment statement specifies a request to an object to bind one or more of its attributes or items. An object may refuse to create or rebind some (or all) attributes or items, raising an exception if you attempt a disallowed creation or rebinding.
A plain assignment can use multiple targets and equals signs (=). For example:
a = b = c = 0
binds variables a, b, and c to the same value, 0. Each time the statement executes, the RHS expression evaluates just once, no matter how many targets are part of the statement. Each target, left to right, is bound to the single object returned by the expression, just as if several simple assignments executed one after the other.
The target in a plain assignment can list two or more references separated by commas, optionally enclosed in parentheses or brackets. For example:
a, b, c = x
This statement requires x to be an iterable with exactly three items, and binds a to the first item, b to the second, and c to the third. This kind of assignment is known as an unpacking assignment. The RHS expression must be an iterable with exactly as many items as there are references in the target; otherwise, Python raises an exception. Each reference in the target gets bound to the corresponding item in the RHS. An unpacking assignment can also be used to swap references:
a, b = b, a
This assignment statement rebinds name a to what name b was bound to, and vice versa. In v3, exactly one of the multiple targets of an unpacking assignment may be preceded by *. That starred target is bound to a list of all items, if any, that were not assigned to other targets. For example, in v3:
first, *middle, last = x
when x is a list, is the same as (but more concise, clearer, more general, and faster than):
first, middle, last = x[0], x[1:-1], x[-1]
Each of these assignments requires x to have at least two items. The second form, compatible with v2, requires the values in x to be a sequence, accessible by numeric index; the first, v3-only, form, is fine with x being any iterable with at least two items. This v3-only feature is known as extended unpacking.
An augmented assignment (sometimes also known as an in-place assignment) differs from a plain assignment in that, instead of an equals sign (=) between the target and the expression, it uses an augmented operator, which is a binary operator followed by =. The augmented operators are +=, -=, *=, /=, //=, %=, **=, |=, >>=, <<=, &=, and ^= (and, in v3 only, @=). An augmented assignment can have only one target on the LHS; augmented assignment doesn’t support multiple targets.
In an augmented assignment, just as in a plain one, Python first evaluates the RHS expression. Then, when the LHS refers to an object that has a special method for the appropriate in-place version of the operator, Python calls the method with the RHS value as its argument. It is up to the method to modify the LHS object appropriately and return the modified object. When the LHS object has no appropriate in-place special method, Python applies the corresponding binary operator to the LHS and RHS objects, then rebinds the target reference to the operator’s result. For example, x+=y is like x=x.__iadd__(y) when x has special method __iadd__ for in-place addition. Otherwise, x+=y is like x=x+y.
Augmented assignment never creates its target reference; the target must already be bound when augmented assignment executes. Augmented assignment can rebind the target reference to a new object, or modify the same object to which the target reference was already bound. Plain assignment, in contrast, can create or rebind the LHS target reference, but it never modifies the object, if any, to which the target reference was previously bound. The distinction between objects and references to objects is crucial here. For example, x=x+y does not modify the object to which name x was originally bound. Rather, it rebinds the name x to refer to a new object. x+=y, in contrast, modifies the object to which the name x is bound, when that object has special method __iadd__; otherwise, x+=y rebinds the name x to a new object, just like x=x+y.
Despite its name, a del statement unbinds references — it does not, per se, delete objects. Object deletion may automatically follow as a consequence, by garbage collection, when no more references to an object exist.
A del statement consists of the keyword del, followed by one or more target references separated by commas (,). Each target can be a variable, attribute reference, indexing, or slicing, just like for assignment statements, and must be bound at the time del executes. When a del target is an identifier, the del statement means to unbind the variable. If the identifier was bound, unbinding it is never disallowed; when requested, it takes place.
In all other cases, the del statement specifies a request to an object to unbind one or more of its attributes or items. An object may refuse to unbind some (or all) attributes or items, raising an exception if you attempt a disallowed unbinding. Unbinding a slicing normally has the same effect as assigning an empty sequence to that slicing, but it is up to the container object to implement this equivalence.
Containers are also allowed to have del cause side effects. For example, assuming del C[2] succeeds, when C is a dict, this makes future references to C[2] invalid (raising KeyError) until and unless you assign to C[2] again; but when C is a list, del C[2] implies that every following item of C "shifts left by one" — so, if C is long enough, future references to C[2] are still valid, but denote a distinct item than they did before the del!