Skip to content

Commit 1afc042

Browse files
authored
Merge pull request realpython#919 from realpython/issue-796
Issue 796 resolved
2 parents 95f203b + 1d1ebf5 commit 1afc042

File tree

1 file changed

+89
-8
lines changed

1 file changed

+89
-8
lines changed

docs/writing/style.rst

Lines changed: 89 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -581,43 +581,124 @@ provide a powerful, concise way to work with lists. Also, the :py:func:`map` and
581581
:py:func:`filter` functions can perform operations on lists using a different,
582582
more concise syntax.
583583

584+
Filtering a list
585+
~~~~~~~~~~~~~~~~
586+
584587
**Bad**:
585588

589+
Never remove items from a list while you are iterating through it.
590+
586591
.. code-block:: python
587592
588593
# Filter elements greater than 4
589594
a = [3, 4, 5]
590-
b = []
591595
for i in a:
592596
if i > 4:
593-
b.append(i)
597+
a.remove(i)
598+
599+
Don't make multiple passes through the list.
600+
601+
.. code-block:: python
602+
603+
while i in a:
604+
a.remove(i)
594605
595606
**Good**:
596607

608+
Python has a few standard ways of filtering lists.
609+
The approach you use depends on
610+
611+
* Python 2.x vs. 3.x
612+
* Lists vs. iterators
613+
* Possible side effects of modifying the original list
614+
615+
Python 2.x vs. 3.x
616+
::::::::::::::::::
617+
618+
Starting with Python 3.0, the :py:func:`filter` function returns an iterator instead of a list.
619+
Wrap it in :py:func:`list` if you truly need a list.
620+
597621
.. code-block:: python
598622
599-
a = [3, 4, 5]
600-
b = [i for i in a if i > 4]
601-
# Or:
602-
b = filter(lambda x: x > 4, a)
623+
list(filter(...))
624+
625+
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)
626+
627+
* comprehensions create a new list object
628+
* generators iterate over the original list
629+
630+
The :py:func:`filter` function
631+
632+
* in 2.x returns a list (use itertools.ifilter if you want an iterator)
633+
* in 3.x returns an iterator
634+
635+
Lists vs. iterators
636+
:::::::::::::::::::
603637

638+
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.
639+
640+
.. code-block:: python
641+
642+
# comprehensions create a new list object
643+
filtered_values = [value for value in sequence if value != x]
644+
# Or (2.x)
645+
filtered_values = filter(lambda i: i != x, sequence)
646+
647+
# generators don't create another list
648+
filtered_values = (value for value in sequence if value != x)
649+
# Or (3.x)
650+
filtered_values = filter(lambda i: i != x, sequence)
651+
# Or (2.x)
652+
filtered_values = itertools.ifilter(lambda i: i != x, sequence)
653+
654+
655+
656+
Possible side effects of modifying the original list
657+
::::::::::::::::::::::::::::::::::::::::::::::::::::
658+
659+
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.
660+
661+
.. code-block:: python
662+
663+
# replace the contents of the original list
664+
sequence[::] = [value for value in sequence if value != x]
665+
# Or
666+
sequence[::] = (value for value in sequence if value != x)
667+
# Or
668+
sequence[::] = filter(lambda value: value != x, sequence)
669+
670+
671+
Modifying the values in a list
672+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
604673
**Bad**:
605674

675+
Remember that assignment never creates a new object. If two or more variables refer to the same list, changing one of them changes them all.
676+
606677
.. code-block:: python
607678
608679
# Add three to all list members.
609680
a = [3, 4, 5]
681+
b = a # a and b refer to the same list object
682+
610683
for i in range(len(a)):
611-
a[i] += 3
684+
a[i] += 3 # b[i] also changes
612685
613686
**Good**:
614687

688+
It's safer to create a new list object and leave the original alone.
689+
615690
.. code-block:: python
616691
617692
a = [3, 4, 5]
693+
b = a
694+
695+
# assign the variable "a" to a new list without changing "b"
618696
a = [i + 3 for i in a]
619-
# Or:
697+
# Or (Python 2.x):
620698
a = map(lambda i: i + 3, a)
699+
# Or (Python 3.x)
700+
a = list(map(lambda i: i + 3, a))
701+
621702
622703
Use :py:func:`enumerate` keep a count of your place in the list.
623704

0 commit comments

Comments
 (0)