If you come from the background of C or C ++, then it is probably easier to rationalize that all variables in Python are really pointers. So statement
a = 1
really looks like
Object *a = new Integer(1);
The is operator verifies that the pointer is equal, and the == operator instead includes a calculation that depends on the type of objects.
A slight complication of this scheme is that if objects are immutable (for example, an integer), then for reasons of efficiency, the above code is really more like
int *a = getFromCacheOrCreateNewInteger(1);
therefore sometimes (but this is an implementation detail) immutable objects can be the same object for is , even if they are created regardless of the logical point of view (for example, it can be 1+1 is 2-1 , but without guarantees):
>>> 1+2 is 2+1 True >>> 99999+1 is 1+99999 False >>>
To add a little more confusion that even if really alla variables in Python are pointers, it is pretty surprising that there is no concept of a pointer in Python, in other words, there is no way to pass a function in which of your variables something should be stored.
To do this, you need to either pass the name (if the variable is global) or pass the setter function, which will be called (if the variable is local). This is not a big annoyance, as in most cases you just need a few return values, and this is handled well by Python:
def foo(x): return x+1, x-1 a, b = foo(12)
Another annoyance is that if you really need to pass the setter to a local variable without a name (like a list item), this cannot be anonymous lambda , because assignment is an expression and lambda only one expression is allowed . However, you can define local functions for this ...
def foo(x, setter): setter(x + 1) def bar(): mylocal = [1,2,3] def setFirst(value): mylocal[0] = value foo(32, setFirst)
(OK. I lied ... it is really possible to use lambda value: mylocal.__setitem__(0, value) , but this is a more or less undesirable incident; lambda so hateful in Python that, when they find out that it is possible, they will probably be added another restriction on the language to prohibit it ;-)).
If you want to change the named local, this is simply not possible in Python 2.x (but possibly with Python 3.x and nonlocal ).
About the question of when copies are made, and instead just copying the pointer, the answer is very simple. Python never makes a copy automatically ... if you want to make a copy, you must do it yourself explicitly. This is why, for example, code is often found, for example:
class Polygon: def __init__(pointlist): self.pointlist = pointlist[:]
The designation [:] here means that the class instance wants to keep a copy of the transferred list, so that when you create an instance of Polygon with a list of points and then modify this list then the geometry does not change.