diff --git a/docs/writing/style.rst b/docs/writing/style.rst index 33ed1ad..8f15a1b 100644 --- a/docs/writing/style.rst +++ b/docs/writing/style.rst @@ -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 `_ -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 +`_ +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.