mirror of
https://github.com/kennethreitz/python-guide.git
synced 2026-06-05 14:50:19 +00:00
Reword the discussion on short ways to manipulate lists
- Remove emphasis on map and filter, in favor of generator expressions. - Move list comprehensions and generator expressions under "Short ways to manipulate lists" rather than "Filtering a list". - Add some examples.
This commit is contained in:
+66
-51
@@ -521,7 +521,7 @@ Conventions
|
||||
Here are some conventions you should follow to make your code easier to read.
|
||||
|
||||
Check if a variable equals a constant
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You don't need to explicitly compare a value to True, or None, or 0 -- you can
|
||||
just add it to the if statement. See `Truth Value Testing
|
||||
@@ -588,9 +588,70 @@ Short Ways to Manipulate Lists
|
||||
|
||||
`List comprehensions
|
||||
<http://docs.python.org/tutorial/datastructures.html#list-comprehensions>`_
|
||||
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.
|
||||
provide a powerful, concise way to work with lists.
|
||||
|
||||
`Generator expressions
|
||||
<http://docs.python.org/tutorial/classes.html#generator-expressions>`_
|
||||
follow almost the same syntax as list comprehensions but return a generator
|
||||
instead of a list.
|
||||
|
||||
Creating a new list requires more work and uses more memory. If you are just going
|
||||
to loop through the new list, prefer using an iterator instead.
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# needlessly allocates a list of all (gpa, name) entires in memory
|
||||
valedictorian = max([(student.gpa, student.name) for student in graduates])
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
valedictorian = max((student.gpa, student.name) for student in graduates)
|
||||
|
||||
|
||||
Use list comprehensions when you really need to create a second list, for
|
||||
example if you need to use the result multiple times.
|
||||
|
||||
|
||||
If your logic is too complicated for a short list comprehension or generator
|
||||
expression, consider using a generator function instead of returning a list.
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def make_batches(items, batch_size):
|
||||
"""
|
||||
>>> list(make_batches([1, 2, 3, 4, 5], batch_size=3))
|
||||
[[1, 2, 3], [4, 5]]
|
||||
"""
|
||||
current_batch = []
|
||||
for item in items:
|
||||
current_batch.append(item)
|
||||
if len(current_batch) == batch_size:
|
||||
yield current_batch
|
||||
current_batch = []
|
||||
yield current_batch
|
||||
|
||||
|
||||
Never use a list comprehension just for its side effects.
|
||||
|
||||
**Bad**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
[print(x) for x in seqeunce]
|
||||
|
||||
**Good**:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
for x in sequence:
|
||||
print(x)
|
||||
|
||||
|
||||
Filtering a list
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -616,52 +677,15 @@ Don't make multiple passes through the list.
|
||||
|
||||
**Good**:
|
||||
|
||||
Python has a few standard ways of filtering lists.
|
||||
The approach you use depends on:
|
||||
|
||||
* Python 2.x vs. 3.x
|
||||
* Lists vs. iterators
|
||||
* Possible side effects of modifying the original list
|
||||
|
||||
Python 2.x vs. 3.x
|
||||
::::::::::::::::::
|
||||
|
||||
Starting with Python 3.0, the :py:func:`filter` function returns an iterator instead of a list.
|
||||
Wrap it in :py:func:`list` if you truly need a list.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
list(filter(...))
|
||||
|
||||
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 :py:func:`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.
|
||||
Use a list comprehension or generator expression.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# 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 don't create another list
|
||||
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)
|
||||
|
||||
|
||||
|
||||
Possible side effects of modifying the original list
|
||||
@@ -673,10 +697,6 @@ Modifying the original list can be risky if there are other variables referencin
|
||||
|
||||
# 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
|
||||
@@ -705,11 +725,6 @@ It's safer to create a new list object and leave the original alone.
|
||||
|
||||
# assign the variable "a" to a new list without changing "b"
|
||||
a = [i + 3 for i in a]
|
||||
# Or (Python 2.x):
|
||||
a = map(lambda i: i + 3, a)
|
||||
# Or (Python 3.x)
|
||||
a = list(map(lambda i: i + 3, a))
|
||||
|
||||
|
||||
Use :py:func:`enumerate` keep a count of your place in the list.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user