Why this matters
In many languages a variable is a box that holds a value, and b = a copies the value into another box. Python does not work that way, and programmers who carry the box picture into Python write bugs: a list "mysteriously" changes because some other part of the program modified it. The correct model is simple and covers every case: names are labels attached to objects. Learn it now and lists, function arguments, default values and copying (all coming later) will behave exactly as you predict.
Assignment is binding
x = 42
This statement does two things, in this order:
- Evaluate the right-hand side. Here that produces (or reuses) an int object with value 42.
- Bind the name
xto that object: record in the current namespace thatxrefers to it.
names objects
----- -------
x ---------------> [ int | 42 ]
A namespace is the table mapping names to objects. At the top level of a script it is the module's global namespace (it really is a dictionary; globals() shows it). The name itself holds no data; it is just an entry pointing at an object. That pointer is called a reference.
Now a second assignment:
y = x
Evaluate the right-hand side: the name x evaluates to the object it refers to. Bind y to that same object. No copy is made.
x ---------\
>----> [ int | 42 ]
y ---------/
Then rebinding:
x = x + 1
Evaluate x + 1: take the object x refers to (42), add 1, producing a new object 43. Bind x to it:
x -------------> [ int | 43 ]
y -------------> [ int | 42 ]
y is unaffected. Assignment never changes an object; it changes what a name refers to.
Identity: id() and is
Each object has an identity, available as id(obj). Two names refer to the same object exactly when their ids are equal. The operator is tests this directly:
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(a == c) # same value?
print(a is c) # same object?
print(a is b)
True
False
True
==asks "do these have equal values?" Each type defines what equal means; for lists, same elements in the same order.isasks "are these the same object?" It compares identities and cannot be customized.
c = [1, 2, 3] built a second list that happens to have the same contents. Two objects, equal values.
a ----\
>----> [ list | 1, 2, 3 ] id: 1001 (say)
b ----/
c ----------> [ list | 1, 2, 3 ] id: 2002
Use == to compare values. Use is almost only for comparing with None (if x is None, next lessons), where there is exactly one such object.
Mutable and immutable objects
Some types allow an object's value to change in place; others never do.
- Immutable:
int,float,bool,str,tuple,None. Once created, the value is fixed. Operations produce new objects. - Mutable:
list,dict,set, and most objects you will create from your own classes. Methods likeappendchange the object itself.
With immutable objects, aliasing is invisible: nobody can change the shared 42, so it does not matter how many names refer to it. With mutable objects, aliasing is visible:
a = [1, 2]
b = a
b.append(3)
print(a)
print(b)
[1, 2, 3]
[1, 2, 3]
b.append(3) did not touch the name a or the name b. It changed the one list object they both refer to.
Compare with strings, which are immutable:
s = "abc"
t = s
t = t + "d"
print(s)
print(t)
abc
abcd
t + "d" cannot change the string "abc"; it creates a new string "abcd" and t is rebound to it.
Note: "Does this line rebind a name, or mutate an object?" is the question to ask whenever two names might share an object.
name = ...rebinds.name.method(...)andname[i] = ...(later) may mutate.
Names have no type
Since a name is just a reference, it can refer to an object of any type, and switch:
thing = 42
print(type(thing))
thing = "forty-two"
print(type(thing))
<class 'int'>
<class 'str'>
The objects have types; the name thing merely pointed at two different objects in turn. That is what dynamic typing means. (Type hints, covered much later, let you document what a name is meant to refer to, but they do not change this behavior.)
del removes a name, not an object
a = [1, 2, 3]
b = a
del a
print(b)
print(a)
[1, 2, 3]
Traceback (most recent call last):
File "main.py", line 5, in <module>
print(a)
^
NameError: name 'a' is not defined
del a removes the binding for a from the namespace. The list survives because b still refers to it. Objects are freed automatically when nothing refers to them any more. In CPython each object keeps a reference count; when it drops to zero, the memory is reclaimed immediately. You never free memory by hand in Python.
A note on small ints and strings
You may notice this in the REPL:
>>> a = 256
>>> b = 256
>>> a is b
True
>>> a = 1000
>>> b = 1000
>>> a is b
False
CPython pre-creates the ints from -5 to 256 and reuses them, and it reuses some strings, purely as a memory optimization. Whether two equal immutable values are the same object is an implementation detail that changes with context and version. This is exactly why you must not use is to compare numbers or strings: it can appear to work and then fail. Python 3.8+ even warns: SyntaxWarning: "is" with 'int' literal. Did you mean "=="?
Common mistakes
- Thinking
b = acopies. It never does. To copy a list, usea.copy()orlist(a)(module 7 covers shallow and deep copies). - Using
isfor value comparison.if answer is "yes":may work in a test and fail in production. Use==. - Expecting rebinding to propagate. After
y = x, rebindingxdoes nothing toy. Only mutation of a shared object is visible through every name. - Reading
=as math equality.x = x + 1is not a contradiction; it means "bind x to the result of x + 1".
Recap
- Assignment evaluates the right side, then binds the name to the resulting object. Names are labels; objects live independently.
b = amakes both names refer to the same object: aliasing, never copying.==compares values;iscompares identity. UseisforNone,==for everything else.- Immutable objects (int, float, str, bool, tuple) cannot change, so aliasing them is harmless; mutable ones (list, dict, set) can, and every alias sees the change.
del nameremoves a binding; objects are freed when no references remain (reference counting).
Going further: paste the examples into pythontutor.com's visualizer (or draw them by hand) to see names and arrows. Ned Batchelder's talk "Facts and Myths about Python Names and Values" is the classic explanation of this model.