lists: list comprehensions¶
List Comprehensions are a simple to make a list from an iterable, by going over every item and performing operations with one line
requirements¶
I open a terminal to run makePythonTdd.sh with
list_comprehensions
as the name of the project./makePythonTdd.sh list_comprehensions
on Windows without Windows Subsystem Linux use makePythonTdd.ps1
./makePythonTdd.ps1 list_comprehensions
it makes the folders and files that are needed, installs packages, runs the first test, and the terminal shows AssertionError
E AssertionError: True is not false tests/test_list_comprehensions.py:7: AssertionError
I hold
ctrl
(windows/linux) oroption
(mac) on the keyboard and use the mouse to click ontests/test_list_comprehensions.py:7
to open it in the editorthen change
True
toFalse
to make the test pass
test_make_a_list_w_a_for_loop¶
red: make it fail¶
I change test_failure
to test_make_a_list_w_a_for_loop
import unittest
class TestListComprehensions(unittest.TestCase):
def test_make_a_list_w_a_for_loop(self):
a_list = []
iterable = range(10)
for item in iterable:
a_list.append(item)
self.assertEqual(a_list, [])
the terminal shows AssertionError
AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] != []
green: make it pass¶
I copy the value from the terminal and use it as the expectation
self.assertEqual(a_list, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
the test passes, the list is no longer empty after calling the append method in the for loop which goes over every item in the iterable
refactor: make it better¶
I add another assert statement
self.assertEqual(a_list, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) self.assertEqual( src.list_comprehensions.for_loop(iterable), a_list )
the terminal shows NameError
NameError: name 'src' is not defined
I add it to the list of Exceptions encountered
# Exceptions Encountered # AssertionError # NameError
then I add an import statement
import src.list_comprehensions import unittest
the terminal shows AttributeError
AttributeError: module 'src.list_comprehensions' has no attribute 'for_loop'
I add the error to the list of Exceptions encountered
# Exceptions Encountered # AssertionError # NameError # AttributeError
I add a function definition to
list_comprehensions.py
def for_loop(): return None
and the terminal shows TypeError
TypeError: for_loop() takes 0 positional arguments but 1 was given
I add the error to the list of Exceptions encountered
# Exceptions Encountered # AssertionError # NameError # AttributeError # TypeError
then I change the signature of the function to take input
def for_loop(argument): return None
the terminal shows AssertionError
AssertionError: None != [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
I add a for loop to the function
def for_loop(argument): result = [] for item in argument: result.append(item) return result
the test passes
result = []
makes an empty listfor item in argument:
loops over the items ofargument
result.append(item)
adds each item fromargument
toresult
return result
returnsresult
after the loop completes
I change the input name from
argument
toiterable
to make it clearerdef for_loop(iterable): result = [] for item in iterable: result.append(item) return result
all tests are still passing
I can make a list from an iterable by using a for loop or the list constructor
test_make_a_list_w_list_comprehensions¶
red: make it fail¶
I add a failing test
def test_make_a_list_w_list_comprehensions(self):
iterable = range(10)
self.assertEqual(
src.list_comprehensions.for_loop(iterable),
[]
)
the terminal shows AssertionError
AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] != []
green: make it pass¶
I make the values in the test match the terminal
self.assertEqual(
src.list_comprehensions.for_loop(iterable),
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
)
the test passes
refactor: make it better¶
I change the expectation to use a list comprehension
self.assertEqual(
src.list_comprehensions.for_loop(iterable),
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[item for item in iterable]
)
the terminal still shows green. I remove the comment then add another assert statement
self.assertEqual(
src.list_comprehensions.for_loop(iterable),
[item for item in iterable]
)
self.assertEqual(
src.list_comprehensions.list_comprehension(iterable),
src.list_comprehensions.for_loop(iterable)
)
the terminal shows AttributeError
AttributeError: module 'src.list_comprehensions' has no attribute 'list_comprehension'
I add a function that uses a list comprehension to list_comprehensions.py
def for_loop(iterable): result = [] for item in iterable: result.append(item) return result def list_comprehension(iterable): return [item for item in iterable]
the test is green again. I made 2 functions, one that uses a for loop and another that uses a list comprehension to do the same thing difference between
a_list = []
for item in iterable:
a_list.append()
and
[item for item in iterable]
the difference between them is that in the first case I have to
When I use list comprehensions, I get the same result with one line that covers all the steps
test_list_comprehensions_w_conditions_i¶
There is more I can do with list comprehensions, I can add conditions when I perform an operation
red: make it fail¶
I add a failing test
def test_list_comprehensions_w_conditions_i(self):
iterable = range(10)
even_numbers = []
for item in iterable:
if item % 2 == 0:
even_numbers.append(item)
self.assertEqual(even_numbers, [])
the terminal shows AssertionError
AssertionError: Lists differ: [0, 2, 4, 6, 8] != []
if item % 2 == 0:
checks if the item initerable
leaves a remainder of0
when divided by2
%
is the modulo operator, it divides the number on the left by the number on the right and returns a remainder
green: make it pass¶
I copy the values from the terminal and paste in the test
self.assertEqual(even_numbers, [0, 2, 4, 6, 8])
the test passes
refactor: make it better¶
I add another assert statement
self.assertEqual(even_numbers, [0, 2, 4, 6, 8]) self.assertEqual( [item for item in iterable], even_numbers )
the terminal shows AssertionError
AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] != [0, 2, 4, 6, 8]
the list comprehension is missing the condition, I add it
self.assertEqual( [item for item in iterable if item % 2 == 0], even_numbers )
the test passes, I add another assert statement
self.assertEqual( [item for item in iterable if item % 2 == 0], even_numbers ) self.assertEqual( src.list_comprehensions.get_even_numbers(iterable), even_numbers )
the terminal shows AttributeError
AttributeError: module 'src.list_comprehensions' has no attribute 'get_even_numbers'
I add a function to
list_comprehensions.py
def list_comprehension(iterable): return [item for item in iterable] def get_even_numbers(iterable): return [item for item in iterable if item % 2 == 0]
the test passes
test_list_comprehensions_w_conditions_ii¶
I add another test
def test_list_comprehensions_w_conditions_ii(self):
iterable = range(10)
odd_numbers = []
for item in iterable:
if item % 2 != 0:
odd_numbers.append(item)
self.assertEqual(odd_numbers, [])
the terminal shows AssertionError
AssertionError: Lists differ: [1, 3, 5, 7, 9] != []
I change the expectation to match
self.assertEqual(odd_numbers, [1, 3, 5, 7, 9])
the test passes. I add another assert statement
self.assertEqual(odd_numbers, [1, 3, 5, 7, 9])
self.assertEqual(
[item for item in iterable],
odd_numbers
)
the terminal shows AssertionError
AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] != [1, 3, 5, 7, 9]
I add the condition to the list comprehension
self.assertEqual(
[item for item in iterable if item % 2 != 0],
odd_numbers
)
the test passes and I add another assert statement
self.assertEqual(
[item for item in iterable if item % 2 != 0],
odd_numbers
)
self.assertEqual(
src.list_comprehensions.get_odd_numbers(iterable),
odd_numbers
)
the terminal shows AttributeError
AttributeError: module 'src.list_comprehensions' has no attribute 'get_odd_numbers'. Did you mean: 'get_even_numbers'?
I add the function
def get_even_numbers(iterable):
return [item for item in iterable if item % 2 == 0]
def get_odd_numbers(iterable):
return [item for item in iterable if item % 2 != 0]
I used the same iterable for every test, I can remove the repetition by using the setUp method
class TestListComprehensions(unittest.TestCase):
def setUp(self):
self.iterable = range(10)
then change all the references to the variable
def test_make_a_list_w_a_for_loop(self):
a_list = []
for item in self.iterable:
a_list.append(item)
self.assertEqual(a_list, list(self.iterable))
self.assertEqual(
src.list_comprehensions.for_loop(self.iterable),
a_list
)
def test_make_a_list_w_list_comprehensions(self):
self.assertEqual(
src.list_comprehensions.for_loop(self.iterable),
[item for item in self.iterable]
)
self.assertEqual(
src.list_comprehensions.list_comprehension(self.iterable),
src.list_comprehensions.for_loop(self.iterable)
)
def test_list_comprehensions_w_conditions_i(self):
even_numbers = []
for item in self.iterable:
if item % 2 == 0:
even_numbers.append(item)
self.assertEqual(
[item for item in self.iterable if item % 2 == 0],
even_numbers
)
self.assertEqual(
src.list_comprehensions.get_even_numbers(self.iterable),
even_numbers
)
def test_list_comprehensions_w_conditions_ii(self):
odd_numbers = []
for item in self.iterable:
if item % 2 != 0:
odd_numbers.append(item)
self.assertEqual(
[item for item in self.iterable if item % 2 != 0],
odd_numbers
)
self.assertEqual(
src.list_comprehensions.get_odd_numbers(self.iterable),
odd_numbers
)
the terminal shows all tests are still passing
review¶
From the tests I can make a list from an iterable by using
a for loop loop
the list constructor
I also ran into the following Exceptions
Would you like to test dictionaries?