2.x vs 3.x, lists vs. iterators

Describe the differences between 2.x and 3.x and suggest situations when iterators would be more appropriate than lists.
This commit is contained in:
Marc Poulin
2018-09-13 11:00:37 -06:00
committed by GitHub
parent 436dec875c
commit e69d7e7657
+57 -25
View File
@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~