summaryrefslogtreecommitdiffstats
path: root/Doc/faq/programming.rst
diff options
context:
space:
mode:
Diffstat (limited to 'Doc/faq/programming.rst')
-rw-r--r--Doc/faq/programming.rst95
1 files changed, 78 insertions, 17 deletions
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index d85563f..c30c2b6 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -292,9 +292,8 @@ What are the "best practices" for using import in a module?
-----------------------------------------------------------
In general, don't use ``from modulename import *``. Doing so clutters the
-importer's namespace. Some people avoid this idiom even with the few modules
-that were designed to be imported in this manner. Modules designed in this
-manner include :mod:`tkinter`, and :mod:`threading`.
+importer's namespace, and makes it much harder for linters to detect undefined
+names.
Import modules at the top of a file. Doing so makes it clear what other modules
your code requires and avoids questions of whether the module name is in scope.
@@ -308,11 +307,6 @@ It's good practice if you import modules in the following order:
directory) -- e.g. mx.DateTime, ZODB, PIL.Image, etc.
3. locally-developed modules
-Never use relative package imports. If you're writing code that's in the
-``package.sub.m1`` module and want to import ``package.sub.m2``, do not just
-write ``from . import m2``, even though it's legal. Write ``from package.sub
-import m2`` instead. See :pep:`328` for details.
-
It is sometimes necessary to move imports to a function or class to avoid
problems with circular imports. Gordon McMillan says:
@@ -343,14 +337,6 @@ module, but loading a module multiple times is virtually free, costing only a
couple of dictionary lookups. Even if the module name has gone out of scope,
the module is probably available in :data:`sys.modules`.
-If only instances of a specific class use a module, then it is reasonable to
-import the module in the class's ``__init__`` method and then assign the module
-to an instance variable so that the module is always available (via that
-instance variable) during the life of the object. Note that to delay an import
-until the class is instantiated, the import must be inside a method. Putting
-the import inside the class but outside of any method still causes the import to
-occur when the module is initialized.
-
Why are default values shared between objects?
----------------------------------------------
@@ -401,7 +387,7 @@ requested again. This is called "memoizing", and can be implemented like this::
# 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 +434,81 @@ arguments a function can accept. For example, given the function definition::
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 factors that produce this result:
+
+1) Variables are simply names that refer to objects. 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`` refer to it.
+2) Lists are :term:`mutable`, which means that you can change their content.
+
+After the call to :meth:`~list.append`, the content of the mutable object has
+changed from ``[]`` to ``[10]``. Since both the variables refer to the same
+object, using either name accesses the modified value ``[10]``.
+
+If we instead assign an immutable object to ``x``::
+
+ >>> 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 that in this case ``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; instead, we are creating a
+new object (the int ``6``) and assigning it to ``x`` (that is, changing which
+object ``x`` refers to). After this assignment we have two objects (the ints
+``6`` and ``5``) and two variables that refer to them (``x`` now refers to
+``6`` but ``y`` still refers to ``5``).
+
+Some operations (for example ``y.append(10)`` and ``y.sort()``) mutate the
+object, whereas superficially similar operations (for example ``y = y + [10]``
+and ``sorted(y)``) create a new object. In general in Python (and in all cases
+in the standard library) a method that mutates an object will return ``None``
+to help avoid getting the two types of operations confused. So if you
+mistakenly write ``y.sort()`` thinking it will give you a sorted copy of ``y``,
+you'll instead end up with ``None``, which will likely cause your program to
+generate an easily diagnosed error.
+
+However, there is one class of operations where the same operation sometimes
+has different behaviors with different types: the augmented assignment
+operators. For example, ``+=`` mutates lists but not tuples or ints (``a_list
++= [1, 2, 3]`` is equivalent to ``a_list.extend([1, 2, 3])`` and mutates
+``a_list``, whereas ``some_tuple += (1, 2, 3)`` and ``some_int += 1`` create
+new objects).
+
+In other words:
+
+* If we have a mutable object (: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 (:class:`str`, :class:`int`, :class:`tuple`,
+ etc.), all the variables that refer to it will always see the same value,
+ but operations that transform that value into a new value always return a new
+ 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)?
---------------------------------------------------------------------