Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1efc78a

Browse filesBrowse files
authored
Merge pull request #971 from gbrova/gbrova/prefer-list-comps-over-map
Prefer list comprehensions over map and filter
2 parents f066175 + c283dbd commit 1efc78a
Copy full SHA for 1efc78a

File tree

Expand file treeCollapse file tree

2 files changed

+74
-71
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+74
-71
lines changed

‎docs/writing/structure.rst

Copy file name to clipboardExpand all lines: docs/writing/structure.rst
+8-20Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -809,16 +809,12 @@ and can be used as a key for a dictionary.
809809

810810
One peculiarity of Python that can surprise beginners is that
811811
strings are immutable. This means that when constructing a string from
812-
its parts, it is much more efficient to accumulate the parts in a list,
813-
which is mutable, and then glue ('join') the parts together when the
814-
full string is needed. One thing to notice, however, is that list
815-
comprehensions are better and faster than constructing a list in a loop
816-
with calls to ``append()``.
817-
818-
One other option is using the map function, which can 'map' a function
819-
('str') to an iterable ('range(20)'). This results in a map object,
820-
which you can then ('join') together just like the other examples.
821-
The map function can be even faster than a list comprehension in some cases.
812+
its parts, appending each part to the string is inefficient because
813+
the entirety of the string is copied on each append.
814+
Instead, it is much more efficient to accumulate the parts in a list,
815+
which is mutable, and then glue (``join``) the parts together when the
816+
full string is needed. List comprehensions are usually the fastest and
817+
most idiomatic way to do this.
822818

823819
**Bad**
824820

@@ -830,7 +826,7 @@ The map function can be even faster than a list comprehension in some cases.
830826
nums += str(n) # slow and inefficient
831827
print nums
832828
833-
**Good**
829+
**Better**
834830

835831
.. code-block:: python
836832
@@ -840,20 +836,12 @@ The map function can be even faster than a list comprehension in some cases.
840836
nums.append(str(n))
841837
print "".join(nums) # much more efficient
842838
843-
**Better**
844-
845-
.. code-block:: python
846-
847-
# create a concatenated string from 0 to 19 (e.g. "012..1819")
848-
nums = [str(n) for n in range(20)]
849-
print "".join(nums)
850-
851839
**Best**
852840

853841
.. code-block:: python
854842
855843
# create a concatenated string from 0 to 19 (e.g. "012..1819")
856-
nums = map(str, range(20))
844+
nums = [str(n) for n in range(20)]
857845
print "".join(nums)
858846
859847
One final thing to mention about strings is that using ``join()`` is not always

‎docs/writing/style.rst

Copy file name to clipboardExpand all lines: docs/writing/style.rst
+66-51Lines changed: 66 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ Conventions
521521
Here are some conventions you should follow to make your code easier to read.
522522

523523
Check if a variable equals a constant
524-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
524+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
525525

526526
You don't need to explicitly compare a value to True, or None, or 0 -- you can
527527
just add it to the if statement. See `Truth Value Testing
@@ -588,80 +588,104 @@ Short Ways to Manipulate Lists
588588

589589
`List comprehensions
590590
<http://docs.python.org/tutorial/datastructures.html#list-comprehensions>`_
591-
provide a powerful, concise way to work with lists. Also, the :py:func:`map` and
592-
:py:func:`filter` functions can perform operations on lists using a different,
593-
more concise syntax.
591+
provide a powerful, concise way to work with lists.
594592

595-
Filtering a list
596-
~~~~~~~~~~~~~~~~
593+
`Generator expressions
594+
<http://docs.python.org/tutorial/classes.html#generator-expressions>`_
595+
follow almost the same syntax as list comprehensions but return a generator
596+
instead of a list.
597597

598-
**Bad**:
598+
Creating a new list requires more work and uses more memory. If you are just going
599+
to loop through the new list, prefer using an iterator instead.
599600

600-
Never remove items from a list while you are iterating through it.
601+
**Bad**:
601602

602603
.. code-block:: python
603604
604-
# Filter elements greater than 4
605-
a = [3, 4, 5]
606-
for i in a:
607-
if i > 4:
608-
a.remove(i)
605+
# needlessly allocates a list of all (gpa, name) entires in memory
606+
valedictorian = max([(student.gpa, student.name) for student in graduates])
609607
610-
Don't make multiple passes through the list.
608+
**Good**:
611609

612610
.. code-block:: python
613611
614-
while i in a:
615-
a.remove(i)
612+
valedictorian = max((student.gpa, student.name) for student in graduates)
613+
614+
615+
Use list comprehensions when you really need to create a second list, for
616+
example if you need to use the result multiple times.
617+
618+
619+
If your logic is too complicated for a short list comprehension or generator
620+
expression, consider using a generator function instead of returning a list.
616621

617622
**Good**:
618623

619-
Python has a few standard ways of filtering lists.
620-
The approach you use depends on:
624+
.. code-block:: python
625+
626+
def make_batches(items, batch_size):
627+
"""
628+
>>> list(make_batches([1, 2, 3, 4, 5], batch_size=3))
629+
[[1, 2, 3], [4, 5]]
630+
"""
631+
current_batch = []
632+
for item in items:
633+
current_batch.append(item)
634+
if len(current_batch) == batch_size:
635+
yield current_batch
636+
current_batch = []
637+
yield current_batch
621638
622-
* Python 2.x vs. 3.x
623-
* Lists vs. iterators
624-
* Possible side effects of modifying the original list
625639
626-
Python 2.x vs. 3.x
627-
::::::::::::::::::
640+
Never use a list comprehension just for its side effects.
628641

629-
Starting with Python 3.0, the :py:func:`filter` function returns an iterator instead of a list.
630-
Wrap it in :py:func:`list` if you truly need a list.
642+
**Bad**:
631643

632644
.. code-block:: python
633645
634-
list(filter(...))
646+
[print(x) for x in seqeunce]
635647
636-
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):
648+
**Good**:
637649

638-
* Comprehensions create a new list object.
639-
* Generators iterate over the original list.
650+
.. code-block:: python
640651
641-
The :py:func:`filter` function:
652+
for x in sequence:
653+
print(x)
642654
643-
* in 2.x returns a list (use itertools.ifilter if you want an iterator)
644-
* in 3.x returns an iterator
645655
646-
Lists vs. iterators
647-
:::::::::::::::::::
656+
Filtering a list
657+
~~~~~~~~~~~~~~~~
658+
659+
**Bad**:
660+
661+
Never remove items from a list while you are iterating through it.
662+
663+
.. code-block:: python
664+
665+
# Filter elements greater than 4
666+
a = [3, 4, 5]
667+
for i in a:
668+
if i > 4:
669+
a.remove(i)
670+
671+
Don't make multiple passes through the list.
672+
673+
.. code-block:: python
674+
675+
while i in a:
676+
a.remove(i)
677+
678+
**Good**:
648679

649-
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.
680+
Use a list comprehension or generator expression.
650681

651682
.. code-block:: python
652683
653684
# comprehensions create a new list object
654685
filtered_values = [value for value in sequence if value != x]
655-
# Or (2.x)
656-
filtered_values = filter(lambda i: i != x, sequence)
657686
658687
# generators don't create another list
659688
filtered_values = (value for value in sequence if value != x)
660-
# Or (3.x)
661-
filtered_values = filter(lambda i: i != x, sequence)
662-
# Or (2.x)
663-
filtered_values = itertools.ifilter(lambda i: i != x, sequence)
664-
665689
666690
667691
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
673697
674698
# replace the contents of the original list
675699
sequence[::] = [value for value in sequence if value != x]
676-
# Or
677-
sequence[::] = (value for value in sequence if value != x)
678-
# Or
679-
sequence[::] = filter(lambda value: value != x, sequence)
680700
681701
682702
Modifying the values in a list
@@ -705,11 +725,6 @@ It's safer to create a new list object and leave the original alone.
705725
706726
# assign the variable "a" to a new list without changing "b"
707727
a = [i + 3 for i in a]
708-
# Or (Python 2.x):
709-
a = map(lambda i: i + 3, a)
710-
# Or (Python 3.x)
711-
a = list(map(lambda i: i + 3, a))
712-
713728
714729
Use :py:func:`enumerate` keep a count of your place in the list.
715730

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.