diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -401,7 +401,7 @@ # Calculate the value result = ... expensive computation ... - _cache[(arg1, arg2)] = result # Store result in the cache + _cache[(arg1, arg2)] = result # Store result in the cache return result You could use a global variable containing a dictionary instead of the default @@ -448,6 +448,70 @@ the values ``42``, ``314``, and ``somevar`` are arguments. +Why did changing list 'y' also change list 'x'? +------------------------------------------------ + +If you wrote code like:: + + >>> x = [] + >>> y = x + >>> y.append(10) + >>> y + [10] + >>> x + [10] + +you might be wondering why appending an element to ``y`` changed ``x`` too. + +There are two reasons: + +1) variables are simply names that refers to object. Doing ``y = x`` doesn't + create a copy of the list -- it creates a new variable ``y`` that refers to + the same object ``x`` refers to. This means that there is only one object + (the list), and both ``x`` and ``y`` refers to it. +2) lists are :term:`mutable`, so you can change their content without having + to create a new object. After the call to :meth:`~list.append`, both the + variables still refers to the same list (i.e. ``[10]``). + +If we assign an immutable object to ``x``, e.g.:: + + >>> x = 5 # ints are immutable + >>> y = x + >>> x = x + 1 # 5 can't be mutated, we are creating a new object here + >>> x + 6 + >>> y + 5 + +we can see how ``x`` and ``y`` are not equal anymore. This is because integers +are :term:`immutable` and when we do ``x = x + 1`` we are not mutating the int +``5`` by incrementing its value, but we are creating a new object (the int +``6``) and assigning it to ``x``. After this assignment we have two objects +(the ints ``6`` and ``5``) and two variables that refer to them (``x`` and +``y`` respectively). + +Also note that some operations (e.g. ``y.append(10)``/``y += [10]`` or +``y.sort()``) mutate the object, whereas seemingly similar operations (e.g. +``y = y + [10]`` or ``sorted(y)``) create a new object. The same operation +might also have different behaviors with different types: ``+=`` mutates lists +but not tuples or ints (``y += [1, 2, 3]`` is equivalent to +``y.extend([1, 2, 3])`` and mutates ``y``, whereas ``t += (1, 2, 3)`` and +``x += 1`` create new objects). + +In other words: + +* if we have a mutable object (e.g. :class:`list`, :class:`dict`, :class:`set`, + etc.), we can use some specific operations to mutate it and all the variables + that refer to it will see + the change; +* if we have an immutable object (e.g. :class:`str`, :class:`int`, :class:`tuple`, + etc.), all the variables that refer to it will always see the same value + (at least as long as they refer to that object). + +If you want to know if two variables refer to the same object or not, you can +use the :keyword:`is` operator, or the built-in function :func:`id`. + + How do I write a function with output parameters (call by reference)? ---------------------------------------------------------------------