diff --git a/docs/writing/style.rst b/docs/writing/style.rst index 4de1f28..e71ffa3 100644 --- a/docs/writing/style.rst +++ b/docs/writing/style.rst @@ -581,21 +581,12 @@ provide a powerful, concise way to work with lists. Also, the :py:func:`map` and :py:func:`filter` functions can perform operations on lists using a different, more concise syntax. -Starting with Python 3.0, the :py:func:`map` and :py:func:`filter` -functions return an iterator instead of a list. If you really need a list, you -should wrap these functions in :py:func`list` like so - -.. code-block:: python - - list(map(...)) - list(filter(...)) - Filtering a list ~~~~~~~~~~~~~~~~ -**Very Bad**: +**Bad**: -Never remove items from a list that you are iterating over. +Never remove items from list while you are iterating through it. Python will lose track of its current position. .. code-block:: python @@ -606,28 +597,69 @@ Python will lose track of its current position. if i > 4: a.remove(i) +Python has standard ways of filtering lists, but there are several things you need to consider -**Bad**: +* Python 2.x vs. 3.x +* Lists vs. iterators +* Creating a new list vs. modifying the original list + +Python 2.x vs. 3.x +:::::::::::::::::: + +* Starting with Python 3.0, the :py:func:`map` and :py:func:`filter` +functions return an iterator instead of a list. If you really need a list, you +should wrap these functions in :py:func`list` like so .. code-block:: python - # Filter elements greater than 4 - a = [3, 4, 5] - b = [] - for i in a: - if i > 4: - b.append(i) + list(map(...)) + list(filter(...)) -**Good**: +* List comprehensions and generator expressions work the same in both 2.x and 3.x (except that comprehensions in 2.x "leak" variables into the enclosing namespace) + + * comprehensions create a new list object + * generators iterate over the original list + +* The filter function + + * in 2.x returns a list (use itertools.ifilter if you want an iterator) + * in 3.x returns an iterator + +Lists vs. iterators +::::::::::::::::::: + +Creating a new list requires more work and uses more memory. If you a just going to loop through the new list, consider using an iterator instead. .. code-block:: python - a = [3, 4, 5] - b = [i for i in a if i > 4] - # Or (Python 2.x): - b = filter(lambda x: x > 4, a) - # Or (Python 3.x) - b = list(filter(lambda x: x > 4, a)) + # comprehensions create a new list object + filtered_values = [value for value in sequence if value != x] + # Or (2.x) + filtered_values = filter(lambda i: i != x, sequence) + + # generators are lazy + filtered_values = (value for value in sequence if value != x) + # Or (3.x) + filtered_values = filter(lambda i: i != x, sequence) + # Or (2.x) + filtered_values = itertools.ifilter(lambda i: i != x, sequence) + + + +Creating a new list vs. modifying the original list +::::::::::::::::::::::::::::::::::::::::::::::::::: + +Modifying the original list can be risky if there are other variables referencing it. But you can use *slice assignment* if you really want to do that. + +.. code-block:: python + + # replace the contents of the original list + sequence[::] = [value for value in sequence if value != x] + # Or + sequence[::] = (value for value in sequence if value != x) + # Or + sequence[::] = filter(lambda value: value != x, sequence) + Modifying the values in a list ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~