what is a function?
A function is code that is callable, this means I can write code to do something one time, and call the name for it to do that thing at a different time from when I write it.
functions can make code simpler, easier to read, test, reuse, maintain and improve - all the good things.
Part of Computer Programming is sending input data to a process and getting output data back
input_data -> process -> output_data
where process is the function. I think of it like mapping a function f in Mathematics with inputs x and output y
in other words
f(x) -> y
function(input_data) -> output_data
the function does something (the process) with input_data and returns output_data as the result.
how to make a function
functions are made with
the def keyword
a name
parentheses and a colon at the end
the code that makes up the function (its body) comes after the colon
def name_of_function():
the body of the function
...
preview
I have these tests by the end of the chapter
1import src.functions
2import unittest
3
4
5def add_x(number):
6 # return 2 + number
7 return 3 + number
8
9
10class TestFunctions(unittest.TestCase):
11
12 def test_why_use_a_function(self):
13 # reality = 1 + 0
14 # reality = 2 + 0
15 reality = add_x(0)
16 # my_expectation = 0
17 # my_expectation = 1
18 # my_expectation = 2
19 my_expectation = 3
20 self.assertEqual(reality, my_expectation)
21
22 # reality = 1 + 1
23 # reality = 2 + 1
24 reality = add_x(1)
25 # my_expectation = 1
26 # my_expectation = 2
27 # my_expectation = 3
28 my_expectation = 4
29 self.assertEqual(reality, my_expectation)
30
31 # reality = 1 + 2
32 # reality = 2 + 2
33 reality = add_x(2)
34 # my_expectation = 2
35 # my_expectation = 3
36 # my_expectation = 4
37 my_expectation = 5
38 self.assertEqual(reality, my_expectation)
39
40 # reality = 1 + 3
41 # reality = 2 + 3
42 reality = add_x(3)
43 # my_expectation = 3
44 # my_expectation = 4
45 # my_expectation = 5
46 my_expectation = 6
47 self.assertEqual(reality, my_expectation)
48
49 # reality = 1 + 4
50 # reality = 2 + 4
51 reality = add_x(4)
52 # my_expectation = 4
53 # my_expectation = 5
54 # my_expectation = 6
55 my_expectation = 7
56 self.assertEqual(reality, my_expectation)
57
58 # reality = 1 + 5
59 # reality = 2 + 5
60 reality = add_x(5)
61 # my_expectation = 5
62 # my_expectation = 6
63 # my_expectation = 7
64 my_expectation = 8
65 self.assertEqual(reality, my_expectation)
66
67 # reality = 1 + 6
68 # reality = 2 + 6
69 reality = add_x(6)
70 # my_expectation = 6
71 # my_expectation = 7
72 # my_expectation = 8
73 my_expectation = 9
74 self.assertEqual(reality, my_expectation)
75
76 # reality = 1 + 7
77 # reality = 2 + 7
78 reality = add_x(7)
79 # my_expectation = 7
80 # my_expectation = 8
81 # my_expectation = 9
82 my_expectation = 10
83 self.assertEqual(reality, my_expectation)
84
85 # reality = 1 + 8
86 # reality = 2 + 8
87 reality = add_x(8)
88 # my_expectation = 8
89 # my_expectation = 9
90 # my_expectation = 10
91 my_expectation = 11
92 self.assertEqual(reality, my_expectation)
93
94 # reality = 1 + 9
95 # reality = 2 + 9
96 reality = add_x(9)
97 # my_expectation = 9
98 # my_expectation = 10
99 # my_expectation = 11
100 my_expectation = 12
101 self.assertEqual(reality, my_expectation)
102
103 def test_making_a_function_w_pass(self):
104 self.assertIs(src.functions.w_pass(), None)
105
106 def test_making_a_function_w_return(self):
107 self.assertIs(src.functions.w_return(), None)
108
109 def test_making_a_function_w_return_none(self):
110 self.assertIs(
111 src.functions.w_return_none(), None
112 )
113
114 def test_what_happens_after_a_function_returns(self):
115 self.assertIs(
116 src.functions.return_is_last(), None
117 )
118
119 def test_constant_function(self):
120 reality = src.functions.constant()
121 my_expectation = 'the same thing'
122 self.assertEqual(reality, my_expectation)
123
124 def test_identity_function(self):
125 reality = src.functions.identity(None)
126 my_expectation = None
127 self.assertEqual(reality, my_expectation)
128
129 reality = src.functions.identity(object)
130 my_expectation = object
131 self.assertEqual(reality, my_expectation)
132
133 def test_w_positional_arguments(self):
134 first, last = 'first', 'last'
135
136 reality = src.functions.w_positional_arguments(
137 first, last,
138 )
139 my_expectation = (first, last)
140 self.assertEqual(reality, my_expectation)
141
142 reality = src.functions.w_positional_arguments(
143 last, first,
144 )
145 my_expectation = (last, first)
146 self.assertEqual(reality, my_expectation)
147
148 first_number, second_number = 0, 1
149 reality = src.functions.w_positional_arguments(
150 first_number, second_number,
151 )
152 my_expectation = (first_number, second_number)
153 self.assertEqual(reality, my_expectation)
154
155 a_tuple = (1, 2, 3, 'n')
156 a_list = [1, 2, 3, 'n']
157 reality = src.functions.w_positional_arguments(
158 a_tuple, a_list,
159 )
160 my_expectation = (a_tuple, a_list)
161 self.assertEqual(reality, my_expectation)
162
163 def test_w_keyword_arguments(self):
164 first, last = 'first', 'last'
165
166 reality = src.functions.w_keyword_arguments(
167 first_input=first, last_input=last,
168 )
169 my_expectation = (first, last)
170 self.assertEqual(reality, my_expectation)
171
172 reality = src.functions.w_keyword_arguments(
173 last_input=last, first_input=first,
174 )
175 my_expectation = (first, last)
176 self.assertEqual(reality, my_expectation)
177
178 reality = src.functions.w_keyword_arguments(
179 last, first,
180 )
181 my_expectation = (last, first)
182 self.assertEqual(reality, my_expectation)
183
184 zero, one = 0, 1
185 reality = src.functions.w_keyword_arguments(
186 last_input=zero, first_input=one,
187 )
188 my_expectation = (one, zero)
189 self.assertEqual(reality, my_expectation)
190
191 a_set = {1, 2, 3, 'n'}
192 a_dictionary = {'key': 'value'}
193 reality = src.functions.w_keyword_arguments(
194 first_input=a_set,
195 last_input=a_dictionary,
196 )
197 my_expectation = (a_set, a_dictionary)
198 self.assertEqual(reality, my_expectation)
199
200 a_tuple = (1, 2, 3, 'n')
201 a_list = [1, 2, 3, 'n']
202 reality = src.functions.w_positional_arguments(
203 first_input=a_list,
204 last_input=a_tuple,
205 )
206 my_expectation = (a_list, a_tuple)
207 self.assertEqual(reality, my_expectation)
208
209 def test_w_args_and_kwargs(self):
210 first, last = 'first', 'last'
211 reality = (
212 src.functions.w_args_and_kwargs(
213 first, last_input=last,
214 )
215 )
216 my_expectation = (first, last)
217 self.assertEqual(reality, my_expectation)
218
219 def test_w_optional_arguments(self):
220 first_name, last_name = 'jane', 'doe'
221 reality = src.functions.w_optional_arguments(
222 first_name,
223 )
224 my_expectation = (first_name, last_name)
225 self.assertEqual(reality, my_expectation)
226
227 first_name, blow = 'joe', 'blow'
228 reality = src.functions.w_optional_arguments(
229 first_name, blow,
230 )
231 my_expectation = (first_name, blow)
232 self.assertEqual(reality, my_expectation)
233
234 first_name = 'john'
235 reality = src.functions.w_optional_arguments(
236 first_input=first_name,
237 )
238 my_expectation = (first_name, last_name)
239 self.assertEqual(reality, my_expectation)
240
241 last_name = 'smith'
242 reality = src.functions.w_optional_arguments(
243 last_input=last_name,
244 first_input=first_name,
245 )
246 my_expectation = (first_name, last_name)
247 self.assertEqual(reality, my_expectation)
248
249 def test_w_unknown_arguments(self):
250 a_tuple = (0, 1)
251 a_dictionary = {'a': 2, 'b': 3}
252 reality = src.functions.w_unknown_arguments(
253 *a_tuple, **a_dictionary
254 )
255 my_expectation = (a_tuple, a_dictionary)
256 self.assertEqual(reality, my_expectation)
257
258 a_tuple = (0, 1)
259 a_dictionary = {'a': 2, 'b': 3, 'c': 4}
260 reality = src.functions.w_unknown_arguments(
261 *a_tuple, **a_dictionary
262 )
263 my_expectation = (
264 a_tuple, a_dictionary
265 )
266 self.assertEqual(reality, my_expectation)
267
268 a_tuple = (0, 1, 2)
269 a_dictionary = {'a': 3, 'b': 4, 'c': 5}
270 reality = src.functions.w_unknown_arguments(
271 *a_tuple, **a_dictionary,
272 )
273 my_expectation = (
274 a_tuple, a_dictionary
275 )
276 self.assertEqual(reality, my_expectation)
277
278 a_tuple = (0, 1, 2, 3)
279 reality = src.functions.w_unknown_arguments(
280 *a_tuple
281 )
282 my_expectation = (a_tuple, {})
283 self.assertEqual(reality, my_expectation)
284
285 a_dictionary = {'a': 4, 'b': 5, 'c': 6, 'd': 7}
286 reality = src.functions.w_unknown_arguments(
287 **a_dictionary
288 )
289 my_expectation = ((), a_dictionary)
290 self.assertEqual(reality, my_expectation)
291
292 reality = src.functions.w_unknown_arguments()
293 my_expectation = ((), {})
294 self.assertEqual(reality, my_expectation)
295
296
297# Exceptions seen
298# AssertionError
299# NameError
300# AttributeError
301# TypeError
302# SyntaxError
questions about functions
Questions to think about as I go through the chapter
start the project
I name this project
functionsI open a terminal
I use uv to make a directory for the project and initialize it
uv init functionsthe terminal shows
Initialized project `functions` at `.../pumping_python/functions`then goes back to the command line.
I change directory to the project
cd functionsthe terminal shows I am in the
functionsfolder.../pumping_python/functionsI make a directory for the source code
mkdir srcthe terminal goes back to the command line.
.../pumping_python/functionsI use the mv program to change the name of
main.pytofunctions.pyand move it to thesrcfoldermv main.py src/functions.pyMove-Item main.py src/functions.pythe terminal goes back to the command line.
I make a directory for the tests
mkdir teststhe terminal goes back to the command line.
I make the
testsdirectory a Python packageDanger
use 2 underscores (__) before and after
initfor__init__.pynot_init_.pytouch tests/__init__.pyNew-Item tests/__init__.pythe terminal goes back to the command line.
I make a Python file for the tests in the
testsdirectorytouch tests/test_functions.pyNew-Item tests/test_functions.pythe terminal goes back to the command line.
I open
test_functions.pyI add the first failing test to
test_functions.py1import unittest 2 3 4class TestFunctions(unittest.TestCase): 5 6 def test_failure(self): 7 self.assertFalse(True)I go back to the terminal to make a requirements file for the Python packages I need
echo "pytest" > requirements.txtthe terminal goes back to the command line.
I add pytest-watcher to the requirements file
echo "pytest-watcher" >> requirements.txtthe terminal goes back to the command line.
I use uv to install pytest-watcher with the requirements file
uv add --requirement requirements.txtthe terminal shows that it installed pytest-watcher and its dependencies.
I add the new files and folders to git for tracking
git add .the terminal goes back to the command line.
I add a git commit message
git commit --all --message 'setup project'the terminal shows
[main (root-commit) a0b12c3] setup project 9 files changed, 148 insertions(+) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 README.md create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 src/functions.py create mode 100644 tests/__init__.py create mode 100644 tests/test_functions.py create mode 100644 uv.lockthen goes back to the command line.
I use pytest-watcher to run the tests automatically
uv run pytest-watcher . --nowthe terminal is my friend, and shows AssertionError
======================== FAILURES ======================== _______________________ TestFunctions.test_failure _______________________ self = <tests.test_functions.TestFunctions testMethod=test_failure> def test_failure(self): > self.assertFalse(True) E AssertionError: True is not false tests/test_functions.py:7: AssertionError ================ short test summary info ================= FAILED tests/test_functions.py::TestFunctions::test_failure - AssertionError: True is not false =================== 1 failed in X.YZs ====================if the terminal does not show the same error, then check
if your
tests/__init__.pyhas two underscores (__) before and afterinitfor__init__.pynot_init_.pyif you ran
echo "pytest-watcher" >> requirements.txt, to addpytest-watcherto the requirements file
fix those errors and try to run
uv run pytest-watcher . --nowagainI add AssertionError to the list of Exceptions seen in
test_functions.py4class TestFunctions(unittest.TestCase): 5 6 def test_failure(self): 7 self.assertFalse(True) 8 9 10# Exceptions seen 11# AssertionErrorthen I change True to False in the assertion
7 self.assertFalse(False)the test passes.
test_why_use_a_function
Why would I use a function when I can just write code to do the thing I want?
RED: make it fail
I change test_failure to
test_why_use_a_functionwith an assertion4class TestFunctions(unittest.TestCase): 5 6 def test_why_use_a_function(self): 7 reality = 1 + 0 8 my_expectation = 0 9 self.assertEqual(reality, my_expectation) 10 11 12# Exceptions seen 13# AssertionErrorthe terminal is my friend, and shows AssertionError
AssertionError: 1 != 0because
1is NOT equal to0
GREEN: make it pass
I change my_expectation to match reality
6 def test_why_use_a_function(self):
7 reality = 1 + 0
8 # my_expectation = 0
9 my_expectation = 1
10 self.assertEqual(reality, my_expectation)
11
12
13 # Exceptions seen
the test passes.
REFACTOR: make it better
I add another assertion
6 def test_why_use_a_function(self): 7 reality = 1 + 0 8 # my_expectation = 0 9 my_expectation = 1 10 self.assertEqual(reality, my_expectation) 11 12 reality = 1 + 1 13 my_expectation = 1 14 self.assertEqual(reality, my_expectation) 15 16 17# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 2 != 1I change
my_expectationto211 reality = 1 + 1 12 # my_expectation = 1 13 my_expectation = 2 14 self.assertEqual(reality, my_expectation) 15 16 17# Exceptions seenthe test passes.
I add another assertion
12 reality = 1 + 1 13 # my_expectation = 1 14 my_expectation = 2 15 self.assertEqual(reality, my_expectation) 16 17 reality = 1 + 2 18 my_expectation = 2 19 self.assertEqual(reality, my_expectation) 20 21 22# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 3 != 2I change
my_expectationto317 reality = 1 + 2 18 # my_expectation = 2 19 my_expectation = 3 20 self.assertEqual(reality, my_expectation) 21 22 23# Exceptions seenthe test passes.
I add an assertion
17 reality = 1 + 2 18 # my_expectation = 2 19 my_expectation = 3 20 self.assertEqual(reality, my_expectation) 21 22 reality = 1 + 3 23 my_expectation = 3 24 self.assertEqual(reality, my_expectation) 25 26 27# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 4 != 3I change
my_expectationto419 reality = 1 + 3 20 # my_expectation = 3 21 my_expectation = 4 22 self.assertEqual(reality, my_expectation) 23 24 25# Exceptions seenthe test passes.
I add an assertion
22 reality = 1 + 3 23 # my_expectation = 3 24 my_expectation = 4 25 self.assertEqual(reality, my_expectation) 26 27 reality = 1 + 4 28 my_expectation = 4 29 self.assertEqual(reality, my_expectation) 30 31 32# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 5 != 4I change
my_expectationto527 reality = 1 + 4 28 # my_expectation = 4 29 my_expectation = 5 30 self.assertEqual(reality, my_expectation) 31 32 33# Exceptions seenthe test passes.
I add an assertion
27 reality = 1 + 4 28 # my_expectation = 4 29 my_expectation = 5 30 self.assertEqual(reality, my_expectation) 31 32 reality = 1 + 5 33 my_expectation = 5 34 self.assertEqual(reality, my_expectation) 35 36 37# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 6 != 5I change
my_expectationto632 reality = 1 + 5 33 # my_expectation = 5 34 my_expectation = 6 35 self.assertEqual(reality, my_expectation) 36 37 38# Exceptions seenthe test passes.
I add another assertion
32 reality = 1 + 5 33 # my_expectation = 5 34 my_expectation = 6 35 self.assertEqual(reality, my_expectation) 36 37 reality = 1 + 6 38 my_expectation = 6 39 self.assertEqual(reality, my_expectation) 40 41 42# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 7 != 6I change
my_expectationto737 reality = 1 + 6 38 # my_expectation = 6 39 my_expectation = 7 40 self.assertEqual(reality, my_expectation) 41 42 43# Exceptions seenthe test passes.
I add an assertion
37 reality = 1 + 6 38 # my_expectation = 6 39 my_expectation = 7 40 self.assertEqual(reality, my_expectation) 41 42 reality = 1 + 7 43 my_expectation = 7 44 self.assertEqual(reality, my_expectation) 45 46 47# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 8 != 7I change
my_expectationto835 reality = 1 + 7 36 # my_expectation = 7 37 my_expectation = 8 38 self.assertEqual(reality, my_expectation) 39 40 41# Exceptions seenthe test passes.
I add another assertion
42 reality = 1 + 7 43 # my_expectation = 7 44 my_expectation = 8 45 self.assertEqual(reality, my_expectation) 46 47 reality = 1 + 8 48 my_expectation = 8 49 self.assertEqual(reality, my_expectation) 50 51 52# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 9 != 8I change
my_expectationto947 reality = 1 + 8 48 # my_expectation = 8 49 my_expectation = 9 50 self.assertEqual(reality, my_expectation) 51 52 53# Exceptions seenthe test passes.
I add an assertion
47 reality = 1 + 8 48 # my_expectation = 8 49 my_expectation = 9 50 self.assertEqual(reality, my_expectation) 51 52 reality = 1 + 9 53 my_expectation = 9 54 self.assertEqual(reality, my_expectation) 55 56 57# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 10 != 9I change
my_expectationto106 def test_why_use_a_function(self): 7 reality = 1 + 0 8 # my_expectation = 0 9 my_expectation = 1 10 self.assertEqual(reality, my_expectation) 11 12 reality = 1 + 1 13 # my_expectation = 1 14 my_expectation = 2 15 self.assertEqual(reality, my_expectation) 16 17 reality = 1 + 2 18 # my_expectation = 2 19 my_expectation = 3 20 self.assertEqual(reality, my_expectation) 21 22 reality = 1 + 3 23 # my_expectation = 3 24 my_expectation = 4 25 self.assertEqual(reality, my_expectation) 26 27 reality = 1 + 4 28 # my_expectation = 4 29 my_expectation = 5 30 self.assertEqual(reality, my_expectation) 31 32 reality = 1 + 5 33 # my_expectation = 5 34 my_expectation = 6 35 self.assertEqual(reality, my_expectation) 36 37 reality = 1 + 6 38 # my_expectation = 6 39 my_expectation = 7 40 self.assertEqual(reality, my_expectation) 41 42 reality = 1 + 7 43 # my_expectation = 7 44 my_expectation = 8 45 self.assertEqual(reality, my_expectation) 46 47 reality = 1 + 8 48 # my_expectation = 8 49 my_expectation = 9 50 self.assertEqual(reality, my_expectation) 51 52 reality = 1 + 9 53 # my_expectation = 9 54 my_expectation = 10 55 self.assertEqual(reality, my_expectation) 56 57 58# Exceptions seenthe test passes.
all those assertions test what happens when I add a number to
1, what if I want to test what happens when I add a number to2? I would have to change1in 10 places. I change1to2for therealityvariables6 def test_why_use_a_function(self): 7 # reality = 1 + 0 8 reality = 2 + 0 9 # my_expectation = 0 10 my_expectation = 1 11 self.assertEqual(reality, my_expectation) 12 13 # reality = 1 + 1 14 reality = 2 + 1 15 # my_expectation = 1 16 my_expectation = 2 17 self.assertEqual(reality, my_expectation) 18 19 # reality = 1 + 2 20 reality = 2 + 2 21 # my_expectation = 2 22 my_expectation = 3 23 self.assertEqual(reality, my_expectation) 24 25 # reality = 1 + 3 26 reality = 2 + 3 27 # my_expectation = 3 28 my_expectation = 4 29 self.assertEqual(reality, my_expectation) 30 31 # reality = 1 + 4 32 reality = 2 + 4 33 # my_expectation = 4 34 my_expectation = 5 35 self.assertEqual(reality, my_expectation) 36 37 # reality = 1 + 5 38 reality = 2 + 5 39 # my_expectation = 5 40 my_expectation = 6 41 self.assertEqual(reality, my_expectation) 42 43 # reality = 1 + 6 44 reality = 2 + 6 45 # my_expectation = 6 46 my_expectation = 7 47 self.assertEqual(reality, my_expectation) 48 49 # reality = 1 + 7 50 reality = 2 + 7 51 # my_expectation = 7 52 my_expectation = 8 53 self.assertEqual(reality, my_expectation) 54 55 # reality = 1 + 8 56 reality = 2 + 8 57 # my_expectation = 8 58 my_expectation = 9 59 self.assertEqual(reality, my_expectation) 60 61 # reality = 1 + 9 62 reality = 2 + 9 63 # my_expectation = 9 64 my_expectation = 10 65 self.assertEqual(reality, my_expectation) 66 67 68# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: 2 != 1I change
my_expectationfor each assertion6 def test_why_use_a_function(self): 7 # reality = 1 + 0 8 reality = 2 + 0 9 # my_expectation = 0 10 # my_expectation = 1 11 my_expectation = 2 12 self.assertEqual(reality, my_expectation) 13 14 # reality = 1 + 1 15 reality = 2 + 1 16 # my_expectation = 1 17 # my_expectation = 2 18 my_expectation = 3 19 self.assertEqual(reality, my_expectation) 20 21 # reality = 1 + 2 22 reality = 2 + 2 23 # my_expectation = 2 24 # my_expectation = 3 25 my_expectation = 4 26 self.assertEqual(reality, my_expectation) 27 28 # reality = 1 + 3 29 reality = 2 + 3 30 # my_expectation = 3 31 # my_expectation = 4 32 my_expectation = 5 33 self.assertEqual(reality, my_expectation) 34 35 # reality = 1 + 4 36 reality = 2 + 4 37 # my_expectation = 4 38 # my_expectation = 5 39 my_expectation = 6 40 self.assertEqual(reality, my_expectation) 41 42 # reality = 1 + 5 43 reality = 2 + 5 44 # my_expectation = 5 45 # my_expectation = 6 46 my_expectation = 7 47 self.assertEqual(reality, my_expectation) 48 49 # reality = 1 + 6 50 reality = 2 + 6 51 # my_expectation = 6 52 # my_expectation = 7 53 my_expectation = 8 54 self.assertEqual(reality, my_expectation) 55 56 # reality = 1 + 7 57 reality = 2 + 7 58 # my_expectation = 7 59 # my_expectation = 8 60 my_expectation = 9 61 self.assertEqual(reality, my_expectation) 62 63 # reality = 1 + 8 64 reality = 2 + 8 65 # my_expectation = 8 66 # my_expectation = 9 67 my_expectation = 10 68 self.assertEqual(reality, my_expectation) 69 70 # reality = 1 + 9 71 reality = 2 + 9 72 # my_expectation = 9 73 # my_expectation = 10 74 my_expectation = 11 75 self.assertEqual(reality, my_expectation) 76 77 78# Exceptions seenthe test passes.
I open a new terminal then change directories to
functionscd functionsthe terminal shows I am in the
functionsfolder.../pumping_python/functionsI add a git commit message
git commit --all --message \ 'add test_why_use_a_function'the terminal shows a summary of the changes then goes back to the command line.
I go back to the terminal where the tests are running
What if I want to test what happens when I add
3to a number? Wait! No more, please! I do not want to have to make a change for each new number, there has to be a better way. I can use a function for the parts that repeat, I add one totest_functions.py1import unittest 2 3 4def add_x(number): 5 return 2 + number 6 7 8class TestFunctions(unittest.TestCase):I use the new function for
realityin the first assertion8class TestFunctions(unittest.TestCase): 9 10 def test_why_use_a_function(self): 11 # reality = 1 + 0 12 # reality = 2 + 0 13 reality = add_x(0) 14 # my_expectation = 0 15 # my_expectation = 1 16 my_expectation = 2 17 self.assertEqual(reality, my_expectation)the test is still green.
I use the
add_xfunction for the other assertions10 def test_why_use_a_function(self): 11 # reality = 1 + 0 12 # reality = 2 + 0 13 reality = add_x(0) 14 # my_expectation = 0 15 # my_expectation = 1 16 my_expectation = 2 17 self.assertEqual(reality, my_expectation) 18 19 # reality = 1 + 1 20 # reality = 2 + 1 21 reality = add_x(1) 22 # my_expectation = 1 23 # my_expectation = 2 24 my_expectation = 3 25 self.assertEqual(reality, my_expectation) 26 27 # reality = 1 + 2 28 # reality = 2 + 2 29 reality = add_x(2) 30 # my_expectation = 2 31 # my_expectation = 3 32 my_expectation = 4 33 self.assertEqual(reality, my_expectation) 34 35 # reality = 1 + 3 36 # reality = 2 + 3 37 reality = add_x(3) 38 # my_expectation = 3 39 # my_expectation = 4 40 my_expectation = 5 41 self.assertEqual(reality, my_expectation) 42 43 # reality = 1 + 4 44 # reality = 2 + 4 45 reality = add_x(4) 46 # my_expectation = 4 47 # my_expectation = 5 48 my_expectation = 6 49 self.assertEqual(reality, my_expectation) 50 51 # reality = 1 + 5 52 # reality = 2 + 5 53 reality = add_x(5) 54 # my_expectation = 5 55 # my_expectation = 6 56 my_expectation = 7 57 self.assertEqual(reality, my_expectation) 58 59 # reality = 1 + 6 60 # reality = 2 + 6 61 reality = add_x(6) 62 # my_expectation = 6 63 # my_expectation = 7 64 my_expectation = 8still green.
Now I only have to make a change in one place if I want to test what happens if I add
3to a number1import unittest 2 3 4def add_x(number): 5 # return 2 + number 6 return 3 + number 7 8 9class TestFunctions(unittest.TestCase):the terminal is my friend, and shows AssertionError
AssertionError: 3 != 2I change the expectations for the assertions one at a time
11 def test_why_use_a_function(self): 12 # reality = 1 + 0 13 # reality = 2 + 0 14 reality = add_x(0) 15 # my_expectation = 0 16 # my_expectation = 1 17 # my_expectation = 2 18 my_expectation = 3 19 self.assertEqual(reality, my_expectation) 20 21 # reality = 1 + 1 22 # reality = 2 + 1 23 reality = add_x(1) 24 # my_expectation = 1 25 # my_expectation = 2 26 # my_expectation = 3 27 my_expectation = 4 28 self.assertEqual(reality, my_expectation) 29 30 # reality = 1 + 2 31 # reality = 2 + 2 32 reality = add_x(2) 33 # my_expectation = 2 34 # my_expectation = 3 35 # my_expectation = 4 36 my_expectation = 5 37 self.assertEqual(reality, my_expectation) 38 39 # reality = 1 + 3 40 # reality = 2 + 3 41 reality = add_x(3) 42 # my_expectation = 3 43 # my_expectation = 4 44 # my_expectation = 5 45 my_expectation = 6 46 self.assertEqual(reality, my_expectation) 47 48 # reality = 1 + 4 49 # reality = 2 + 4 50 reality = add_x(4) 51 # my_expectation = 4 52 # my_expectation = 5 53 # my_expectation = 6 54 my_expectation = 7 55 self.assertEqual(reality, my_expectation) 56 57 # reality = 1 + 5 58 # reality = 2 + 5 59 reality = add_x(5) 60 # my_expectation = 5 61 # my_expectation = 6 62 # my_expectation = 7 63 my_expectation = 8 64 self.assertEqual(reality, my_expectation) 65 66 # reality = 1 + 6 67 # reality = 2 + 6 68 reality = add_x(6) 69 # my_expectation = 6 70 # my_expectation = 7 71 # my_expectation = 8 72 my_expectation = 9 73 self.assertEqual(reality, my_expectation) 74 75 # reality = 1 + 7 76 # reality = 2 + 7 77 reality = add_x(7) 78 # my_expectation = 7 79 # my_expectation = 8 80 # my_expectation = 9 81 my_expectation = 10 82 self.assertEqual(reality, my_expectation) 83 84 # reality = 1 + 8 85 # reality = 2 + 8 86 reality = add_x(8) 87 # my_expectation = 8 88 # my_expectation = 9 89 # my_expectation = 10 90 my_expectation = 11 91 self.assertEqual(reality, my_expectation) 92 93 # reality = 1 + 9 94 # reality = 2 + 9 95 reality = add_x(9) 96 # my_expectation = 9 97 # my_expectation = 10 98 # my_expectation = 11 99 my_expectation = 12 100 self.assertEqual(reality, my_expectation) 101 102 103# Exceptions seenthe test passes.
I add a git commit message in the other terminal
git commit --all --message 'extract add_x function'the terminal shows a summary of the changes then goes back to the command line.
I can use a function to remove repetition. Is there a better way to handle the changing results?
test_making_a_function_w_pass
I can make a function with the pass keyword
RED: make it fail
I go back to the terminal where the tests are running
I add a new test to
test_functions.py93 # reality = 1 + 9 94 # reality = 2 + 9 95 reality = add_x(9) 96 # my_expectation = 9 97 # my_expectation = 10 98 # my_expectation = 11 99 my_expectation = 12 100 self.assertEqual(reality, my_expectation) 101 102 def test_making_a_function_w_pass(self): 103 self.assertIs(src.functions.w_pass(), None) 104 105 106# Exceptions seenthe terminal is my friend, and shows NameError
NameError: name 'src' is not definedbecause Python does not know what I mean by
srcsince I do not have a definition for it intest_functions.py
GREEN: make it pass
I add NameError to the list of Exceptions seen
106# Exceptions seen 107# AssertionError 108# NameErrorI add an import statement at the top of the file
1import src.functions 2import unittest 3 4 5class TestFunctions(unittest.TestCase):import src.functionsbrings in an object for thefunctions.pymodule from thesrcfolder so I can use it intest_functions.pyI like to sort my import statements alphabetically
the terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_pass'because
functions.pyin thesrcfolder does not have anything namedw_passinside it
I add AttributeError to the list of Exceptions seen
107# Exceptions seen 108# AssertionError 109# NameError 110# AttributeErrorI open
functions.pyfrom thesrcfolderI delete the text in the file then add a function definition to
functions.py1def w_pass(): 2 passthe assertion -
self.assertIs(src.functions.w_pass(), None)checks if the result of a call tow_passinfunctions.pyin thesrcfolder also known assrc.functions.w_pass, is the same object as Nonethe function definition simply says pass and the test passes.
pass is a special keyword that allows the function definition to follow Python language rules (the function must have a body)
the test passes because all functions return None by default, as if they have an invisible line that says return None, which leads me to the next test, but first git business
I add a git commit message in the other terminal
git commit --all --message \ 'add test_making_a_function_w_pass'the terminal shows a summary of the changes then goes back to the command line.
test_making_a_function_w_return
I can also make a function with a return statement
RED: make it fail
I go back to the terminal where the tests are running
I add a new failing test to
test_functions.py103 def test_making_a_function_w_pass(self): 104 self.assertIs(src.functions.w_pass(), None) 105 106 def test_making_a_function_w_return(self): 107 self.assertIs(src.functions.w_return(), None) 108 109 110# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_return'because
functions.pyin thesrcfolder does not have anything with the namew_returnin it
GREEN: make it pass
I add the new function with the pass keyword to functions.py
1def w_pass():
2 pass
3
4
5def w_return():
6 pass
the test passes.
REFACTOR: make it better
I change pass to a return statement
5def w_return(): 6 # pass 7 returnthe assertion -
self.assertIs(src.functions.w_return(), None)checks if the result of a call tow_returninfunctions.pyin thesrcfolder also known assrc.functions.w_return, is the same object as Nonethe function definition simply says return and the test passes.
return is a special keyword that is used to send output from a function.
the test is still green because all functions return None by default, as if they have an invisible line that says return None
I remove the commented line
5def w_return(): 6 returnI add a git commit message in the other terminal
git commit --all --message \ 'add test_making_a_function_w_return'the terminal shows a summary of the changes then goes back to the command line.
I have two functions with different statements, and the tests show that they both return None
src.functions.w_pass()
pass
src.functions.w_return()
return
their contents are different, their results are the same because “all functions return None by default, as if they have an invisible line that says return None”, which leads me to the next test.
test_making_a_function_w_return_none
I can make a function with a return statement that says exactly what the function returns
RED: make it fail
I go back to the terminal where the tests are running
I add another failing test to
test_functions.py106 def test_making_a_function_w_return(self): 107 self.assertIs(src.functions.w_return(), None) 108 109 def test_making_a_function_w_return_none(self): 110 self.assertIs( 111 src.functions.w_return_none(), None 112 ) 113 114 115# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_return_none'because
w_return_noneis not defined infunctions.pyin thesrcfolder
GREEN: make it pass
I add a function definition to functions.py
5def w_return():
6 return
7
8
9def w_return_none():
10 return
the test passes.
REFACTOR: make it better
I add None to the return statement
9def w_return_none(): 10 # return 11 return Nonethe test is still green.
I change None to
'something'9def w_return_none(): 10 # return 11 # return None 12 return 'something'the terminal is my friend, and shows AssertionError
AssertionError: 'something' is not Nonebecause the assertion expects None and the function returns
'something'I undo the change
9def w_return_none(): 10 # return 11 return None 12 # return 'something'the test is green again.
I remove the commented lines
9def w_return_none(): 10 return NoneI add a git commit message in the other terminal
git commit --all --message \ 'add test_making_a_function_w_return_none'the terminal shows a summary of the changes then goes back to the command line.
I have three functions with different statements, and the tests show that they all return None
src.functions.w_pass()
pass
src.functions.w_return()
return
src.functions.w_return_none()
return None
their contents are different, their results are the same because “all functions return None by default, as if they have an invisible line that says …”
I like to write my functions with return None, so that anyone can see what the function returns without having to think about it.
test_what_happens_after_functions_return
The return statement is the last thing to run in a function
RED: make it fail
I go back to the terminal where the tests are running
I add a test to
test_functions.py109 def test_making_a_function_w_return_none(self): 110 self.assertIs( 111 src.functions.w_return_none(), None 112 ) 113 114 def test_what_happens_after_functions_return(self): 115 self.assertIs( 116 src.functions.return_is_last(), None 117 ) 118 119 120# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'return_is_last'because
functions.pydoes not have a definition for it, yet
GREEN: make it pass
I add a function to functions.py
9def w_return_none():
10 return None
11
12
13def return_is_last():
14 return None
the test passes.
REFACTOR: make it better
I add a return statement
13def return_is_last(): 14 return 'something' 15 return Nonethe terminal is my friend, and shows AssertionError
AssertionError: 'something' is not Nonebecause the assertion expects None and the function returns
'something'the function does not run the second return statement because the return statement is the last thing to run in a function, which means the second return statement will never run. It is not reachable (this is called dead code).
Tip
The Integrated Development Environment (IDE) shows that the second return statement will not run by graying it out
I move
return None, to make it the first return statement13def return_is_last(): 14 return None 15 return 'something'the test is green again
I change the second return statement as a reminder
13def return_is_last(): 14 return None 15 return 'will NEVER run'the second return statement is now like a comment, and the test is still green because the return statement is the last thing to run in a function
I add a git commit message in the other terminal
git commit --all --message \ 'add test_what_happens_after_functions_return'the terminal shows a summary of the changes then goes back to the command line.
test_constant_function
constant functions always return the same thing when they are called
RED: make it fail
I go back to the terminal where the tests are running
I add a test to
test_functions.py114 def test_what_happens_after_a_function_returns(self): 115 self.assertIs( 116 src.functions.return_is_last(), None 117 ) 118 119 def test_constant_function(self): 120 reality = src.functions.constant() 121 my_expectation = 'the same thing' 122 self.assertEqual(reality, my_expectation) 123 124 125# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'constant'because I have not added a definition for
constantinfunctions.pyin thesrcfolder
GREEN: make it pass
I add the function to
functions.py13def return_is_last(): 14 return None 15 return 'will never run' 16 17 18def constant(): 19 return Nonethe terminal is my friend, and shows AssertionError
AssertionError: None != 'the same thing'because the assertion expects
'the same thing'and the function returns NoneI change the return statement to give the test what it wants
18def constant(): 19 # return None 20 return 'the same thing'the test passes.
I remove the commented line
18def constant(): 19 return 'the same thing'I add a git commit message in the other terminal
git commit --all --message 'add test_constant_function'the terminal shows a summary of the changes then goes back to the command line.
A constant function always returns the same thing when called, I can use them in place of variables, though the number of cases where they are faster than variables is pretty small. It is something like if the function is called less than 10 times (who’s counting?)
test_identity_function
The identity function returns its input as output, it is also in the Truth Table chapter in test_logical_identity
RED: make it fail
I go back to the terminal where the tests are running
I add a failing test to
test_functions.py119 def test_constant_function(self): 120 reality = src.functions.constant() 121 my_expectation = 'the same thing' 122 self.assertEqual(reality, my_expectation) 123 124 def test_identity_function(self): 125 reality = src.functions.identity(None) 126 my_expectation = None 127 self.assertEqual(reality, my_expectation) 128 129 130# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'identity'is it because
functions.pyhas noidentity?
GREEN: make it pass
I add a function for
identitytofunctions.py18def constant(): 19 return 'the same thing' 20 21 22def identity(): 23 return Nonethe terminal is my friend, and shows TypeError
TypeError: identity() takes 0 positional arguments but 1 was givenbecause the definition for
identitydoes not allow calling it with inputs and the test sends None as inputI add TypeError to the list of Exceptions seen in
test_functions.py130# Exceptions seen 131# AssertionError 132# NameError 133# AttributeError 134# TypeErrorI add a name in parentheses for the
identityfunction to take input, infunctions.py22# def identity(): 23def identity(the_input): 24 return Nonethe test passes. I am genius.
REFACTOR: make it better
The requirement for the identity function is that it returns the same thing it is given, this test passes when None is given as input.
Does it pass when another value is given or does it always return None? Time to test it
I add a new assertion to test_identity_function in
test_functions.py124 def test_identity_function(self): 125 reality = src.functions.identity(None) 126 my_expectation = None 127 self.assertEqual(reality, my_expectation) 128 129 reality = src.functions.identity(object) 130 my_expectation = object 131 self.assertEqual(reality, my_expectation) 132 133 134# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: None != <class 'object'>because the function always returns None not
<class 'object'>or what it receives as input. I am not all the way genius, yetI make the
identityfunction infunctions.pyreturn what it gets22# def identity(): 23def identity(the_input): 24 # return None 25 return the_inputthe test passes.
I remove the commented lines
22def identity(the_input): 23 return the_inputI add a git commit message in the other terminal
git commit --all --message 'add test_identity_function'the terminal shows a summary of the changes then goes back to the command line.
I sometimes use the Identity Function when I am testing, to see if my test is connected to what I am testing. If I can send something (input) and get it back, I can start making changes to see how it affects the output.
test_w_positional_arguments
So far, the functions take no input or one input, the next tests use functions that take more than one input.
RED: make it fail
I go back to the terminal where the tests are running
I add a failing test to
test_functions.py129 reality = src.functions.identity(object) 130 my_expectation = object 131 self.assertEqual(reality, my_expectation) 132 133 def test_w_positional_arguments(self): 134 reality = src.functions.w_positional_arguments( 135 'first', 'last', 136 ) 137 my_expectation = ('first', 'last') 138 self.assertEqual(reality, my_expectation) 139 140 141# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_positional_arguments'because …
GREEN: make it pass
I add the function to
functions.py22def identity(the_input): 23 return the_input 24 25 26def w_positional_arguments(): 27 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_positional_arguments() takes 0 positional arguments but 2 were givenbecause the definition for
w_positional_argumentsdoes not allow inputs and the test sends two in the call ('first'and'last')I make the function take input by adding a name in parentheses
26# def w_positional_arguments(): 27def w_positional_arguments(first_input): 28 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_positional_arguments() takes 1 positional argument but 2 were givenbecause the definition for
w_positional_argumentsnow allows only one input and the test sends two in the call ('first'and'last')I make
w_positional_argumentstake another input by adding another name in parentheses26# def w_positional_arguments(): 27# def w_positional_arguments(first_input): 28def w_positional_arguments(first_input, last_input): 29 return Nonethe terminal is my friend, and shows AssertionError
AssertionError: None != ('first', 'last')because the function returns None and the assertion expects
('first', 'last')I change the return statement to make the function return its inputs as output
26# def w_positional_arguments(): 27# def w_positional_arguments(first_input): 28def w_positional_arguments(first_input, last_input): 29 # return None 30 return first_input, last_inputthe test passes, because the function always returns
first_input, last_inputand the call in the test sends'first'asfirst_inputand'last'aslast_input, which is equal tomy_expectation
REFACTOR: make it better
I remove the commented lines
22def identity(the_input): 23 return the_input 24 25 26def w_positional_arguments(first_input, last_input): 27 return first_input, last_inputThe problem with giving arguments this way is that they always have to be in the order the function expects or I get something different. I add an assertion to show this in test_w_positional_arguments in
test_functions.py133 def test_w_positional_arguments(self): 134 reality = src.functions.w_positional_arguments( 135 'first', 'last', 136 ) 137 my_expectation = ('first', 'last') 138 self.assertEqual(reality, my_expectation) 139 140 reality = src.functions.w_positional_arguments( 141 'last', 'first', 142 ) 143 my_expectation = ('first', 'last') 144 self.assertEqual(reality, my_expectation) 145 146 147# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('last', 'first') != ('first', 'last')because the function always returns
first_input, last_inputand the call in this test sends'last'asfirst_inputand'first'aslast_inputI change
my_expectationto matchreality140 reality = src.functions.w_positional_arguments( 141 'last', 'first', 142 ) 143 # my_expectation = ('first', 'last') 144 my_expectation = ('last', 'first') 145 self.assertEqual(reality, my_expectation) 146 147 148# Exceptions seenthe test passes.
I add variables to use them to remove repetition of
'first'and'last'133 def test_w_positional_arguments(self): 134 first, last = 'first', 'last' 135 136 reality = src.functions.w_positional_arguments( 137 'first', 'last', 138 ) 139 my_expectation = ('first', 'last') 140 self.assertEqual(reality, my_expectation)I use the new variables to remove repetition of
'first'and'last'133 def test_w_positional_arguments(self): 134 first, last = 'first', 'last' 135 136 reality = src.functions.w_positional_arguments( 137 # 'first', 'last', 138 first, last, 139 ) 140 # my_expectation = ('first', 'last') 141 my_expectation = (first, last) 142 self.assertEqual(reality, my_expectation) 143 144 reality = src.functions.w_positional_arguments( 145 # 'last', 'first', 146 last, first, 147 ) 148 # my_expectation = ('first', 'last') 149 # my_expectation = ('last', 'first') 150 my_expectation = (last, first) 151 self.assertEqual(reality, my_expectation) 152 153 154# Exceptions seenthe test is still green.
I add another assertion
144 reality = src.functions.w_positional_arguments( 145 # 'last', 'first', 146 last, first, 147 ) 148 # my_expectation = ('first', 'last') 149 # my_expectation = ('last', 'first') 150 my_expectation = (last, first) 151 self.assertEqual(reality, my_expectation) 152 153 first_number, second_number = 0, 1 154 reality = src.functions.w_positional_arguments( 155 first_number, second_number, 156 ) 157 my_expectation = (second_number, first_number) 158 self.assertEqual(reality, my_expectation) 159 160 161# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: (0, 1) != (1, 0)because the function always returns
first_input, last_inputand the call in this test sends0asfirst_inputand1aslast_inputI change
my_expectationto matchreality153 first_number, second_number = 0, 1 154 reality = src.functions.w_positional_arguments( 155 first_number, second_number, 156 ) 157 # my_expectation = (second_number, first_number) 158 my_expectation = (first_number, second_number) 159 self.assertEqual(reality, my_expectation) 160 161 162# Exceptions seenthe test passes.
I add one more assertion
153 first_number, second_number = 0, 1 154 reality = src.functions.w_positional_arguments( 155 first_number, second_number, 156 ) 157 # my_expectation = (second_number, first_number) 158 my_expectation = (first_number, second_number) 159 self.assertEqual(reality, my_expectation) 160 161 a_tuple = (1, 2, 3, 'n') 162 a_list = [1, 2, 3, 'n'] 163 reality = src.functions.w_positional_arguments( 164 a_list, a_tuple, 165 ) 166 my_expectation = (a_tuple, a_list) 167 self.assertEqual(reality, my_expectation) 168 169 170# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ((1, 2, 3, 'n'), [1, 2, 3, 'n']) != ([1, 2, 3, 'n'], (1, 2, 3, 'n'))because the function always returns
first_input, last_inputand the call in this test sends(1, 2, 3, 'n')asfirst_inputand[1, 2, 3, 'n']aslast_inputI change
realityto matchmy_expectation161 a_tuple = (1, 2, 3, 'n') 162 a_list = [1, 2, 3, 'n'] 163 reality = src.functions.w_positional_arguments( 164 # a_list, a_tuple, 165 a_tuple, a_list, 166 ) 167 my_expectation = (a_tuple, a_list) 168 self.assertEqual(reality, my_expectation) 169 170 171# Exceptions seenthe test passes.
I remove the commented lines
133 def test_w_positional_arguments(self): 134 first, last = 'first', 'last' 135 136 reality = src.functions.w_positional_arguments( 137 first, last, 138 ) 139 my_expectation = (first, last) 140 self.assertEqual(reality, my_expectation) 141 142 reality = src.functions.w_positional_arguments( 143 last, first, 144 ) 145 my_expectation = (last, first) 146 self.assertEqual(reality, my_expectation) 147 148 first_number, second_number = 0, 1 149 reality = src.functions.w_positional_arguments( 150 first_number, second_number, 151 ) 152 my_expectation = (first_number, second_number) 153 self.assertEqual(reality, my_expectation) 154 155 a_tuple = (1, 2, 3, 'n') 156 a_list = [1, 2, 3, 'n'] 157 reality = src.functions.w_positional_arguments( 158 a_tuple, a_list, 159 ) 160 my_expectation = (a_tuple, a_list) 161 self.assertEqual(reality, my_expectation) 162 163 164# Exceptions seenI add a git commit message in the other terminal
git commit --all --message \ 'add test_w_positional_arguments'the terminal shows a summary of the changes then goes back to the command line.
test_w_keyword_arguments
The tests show that positional arguments must always be given in the right order. What if I forget the order? What if there are many inputs?
I can use Keyword Arguments to make sure the function always gets the values for the inputs it expects, that way it does what I want even when I send inputs out of order.
RED: make it fail
I go back to the terminal where the tests are running
I add a new test to
test_functions.py155 a_tuple = (1, 2, 3, 'n') 156 a_list = [1, 2, 3, 'n'] 157 reality = src.functions.w_positional_arguments( 158 a_tuple, a_list, 159 ) 160 my_expectation = (a_tuple, a_list) 161 self.assertEqual(reality, my_expectation) 162 163 def test_w_keyword_arguments(self): 164 reality = src.functions.w_keyword_arguments( 165 first_input='first', last_input='last', 166 ) 167 my_expectation = ('first', 'last') 168 self.assertEqual(reality, my_expectation) 169 170 171# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_keyword_arguments'because
functions.pyin thesrcfolder does not have a definition forw_keyword_arguments
GREEN: make it pass
I add a function definition to
functions.py26def w_positional_arguments(first_input, last_input): 27 return first_input, last_input 28 29 30def w_keyword_arguments(): 31 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_keyword_arguments() got an unexpected keyword argument 'first_input'because the definition for
w_keyword_argumentsdoes not allow inputs and the test uses two in the call (first_inputandlast_input)I add the name of the unexpected argument in parentheses
30# def w_keyword_arguments(): 31def w_keyword_arguments(first_input): 32 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_keyword_arguments() got an unexpected keyword argument 'last_input'. Did you mean 'first_input'?because the definition for
w_keyword_argumentsallows one input (first_input) and the test uses two in the call (first_inputandlast_input)I add a name for the second argument in parentheses
30# def w_keyword_arguments(): 31# def w_keyword_arguments(first_input): 32def w_keyword_arguments(first_input, second_input): 33 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_keyword_arguments() got an unexpected keyword argument 'last_input'. Did you mean 'first_input'?because the definition for
w_keyword_argumentsallows two inputs with the namesfirst_inputandsecond_input, and the test calls the function withfirst_inputandlast_input, the names must match when I am using keyword argumentsI change the name of the second argument to match the name used in the call
30# def w_keyword_arguments(): 31# def w_keyword_arguments(first_input): 32# def w_keyword_arguments(first_input, second_input): 33def w_keyword_arguments(first_input, last_input): 34 return Nonethe terminal is my friend, and shows AssertionError
AssertionError: None != ('first', 'last')because the function returns None and the assertion expects
('first', 'last')I change the return statement to make the function return its inputs
30# def w_keyword_arguments(): 31# def w_keyword_arguments(first_input): 32# def w_keyword_arguments(first_input, second_input): 33def w_keyword_arguments(first_input, last_input): 34 # return None 35 return first_input, last_inputthe test passes.
REFACTOR: make it better
I remove the commented lines
26def w_positional_arguments(first_input, last_input): 27 return first_input, last_input 28 29 30def w_keyword_arguments(first_input, last_input): 31 return first_input, last_inputI add another assertion with the keyword arguments given out of order in test_w_keyword_arguments in
test_functions.py163 def test_w_keyword_arguments(self): 164 reality = src.functions.w_keyword_arguments( 165 first_input='first', last_input='last', 166 ) 167 my_expectation = ('first', 'last') 168 self.assertEqual(reality, my_expectation) 169 170 reality = src.functions.w_keyword_arguments( 171 last_input='last', first_input='first', 172 ) 173 my_expectation = ('last', 'first') 174 self.assertEqual(reality, my_expectation) 175 176 177# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('first', 'last') != ('last', 'first')the order the function returns the values stayed the same this time, because it always returns
first_input, last_input.Compare this call that uses positional arguments and its result
src.functions.w_positional_arguments('last', 'first') ('last', 'first')with this call that uses keyword arguments and its result
src.functions.w_keyword_arguments( last_input='last', first_input='first', ) ('first', 'last')in both cases the function returns
first_input, last_inputI change
my_expectationto matchreality170 reality = src.functions.w_keyword_arguments( 171 last_input='last', first_input='first', 172 ) 173 # my_expectation = ('last', 'first') 174 my_expectation = ('first', 'last') 175 self.assertEqual(reality, my_expectation) 176 177 178# Exceptions seenthe test passes. The order does not matter when I use keyword arguments.
I add variables to use them to remove repetition of
'first'and'last'from the test163 def test_w_keyword_arguments(self): 164 first, last = 'first', 'last' 165 166 reality = src.functions.w_keyword_arguments( 167 first_input='first', last_input='last', 168 ) 169 my_expectation = ('first', 'last') 170 self.assertEqual(reality, my_expectation)I use the new variables to remove repetition of
'first'and'last'from the test163 def test_w_keyword_arguments(self): 164 first, last = 'first', 'last' 165 166 reality = src.functions.w_keyword_arguments( 167 # first_input='first', last_input='last', 168 first_input=first, last_input=last, 169 ) 170 # my_expectation = ('first', 'last') 171 my_expectation = (first, last) 172 self.assertEqual(reality, my_expectation) 173 174 reality = src.functions.w_keyword_arguments( 175 # last_input='last', first_input='first', 176 last_input=last, first_input=first, 177 ) 178 # my_expectation = ('last', 'first') 179 # my_expectation = ('first', 'last') 180 my_expectation = (first, last) 181 self.assertEqual(reality, my_expectation) 182 183 184# Exceptions seenthe test is still green.
I can still call the function the same way I did in test_w_positional_arguments (without using the names). I add an assertion to show this
174 reality = src.functions.w_keyword_arguments( 175 # last_input='last', first_input='first', 176 last_input=last, first_input=first, 177 ) 178 # my_expectation = ('last', 'first') 179 # my_expectation = ('first', 'last') 180 my_expectation = (first, last) 181 self.assertEqual(reality, my_expectation) 182 183 reality = src.functions.w_keyword_arguments( 184 last, first, 185 ) 186 my_expectation = (first, last) 187 self.assertEqual(reality, my_expectation) 188 189 190# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('last', 'first') != ('first', 'last')because the function uses the order (positions) when I do not use the names
I change
my_expectationto matchreality183 reality = src.functions.w_keyword_arguments( 184 last, first, 185 ) 186 # my_expectation = (first, last) 187 my_expectation = (last, first) 188 self.assertEqual(reality, my_expectation) 189 190 191# Exceptions seenthe test passes.
I add another assertion
183 reality = src.functions.w_keyword_arguments( 184 last, first, 185 ) 186 # my_expectation = (first, last) 187 my_expectation = (last, first) 188 self.assertEqual(reality, my_expectation) 189 190 zero, one = 0, 1 191 reality = src.functions.w_keyword_arguments( 192 last_input=zero, first_input=one, 193 ) 194 my_expectation = (zero, one) 195 self.assertEqual(reality, my_expectation) 196 197 198# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: (1, 0) != (0, 1)I change
my_expectationto matchreality190 zero, one = 0, 1 191 reality = src.functions.w_keyword_arguments( 192 last_input=zero, first_input=one, 193 ) 194 # my_expectation = (zero, one) 195 my_expectation = (one, zero) 196 self.assertEqual(reality, my_expectation) 197 198 199# Exceptions seenthe test passes.
I add an assertion
190 zero, one = 0, 1 191 reality = src.functions.w_keyword_arguments( 192 last_input=zero, first_input=one, 193 ) 194 # my_expectation = (zero, one) 195 my_expectation = (one, zero) 196 self.assertEqual(reality, my_expectation) 197 198 a_set = {1, 2, 3, 'n'} 199 a_dictionary = {'key': 'value'} 200 reality = src.functions.w_keyword_arguments( 201 first_input=a_dictionary, 202 last_input=a_set, 203 ) 204 my_expectation = (a_set, a_dictionary) 205 self.assertEqual(reality, my_expectation) 206 207 208# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ({'key': 'value'}, {1, 2, 3, 'n'}) != ({1, 2, 3, 'n'}, {'key': 'value'})I change
realityto matchmy_expectation198 a_set = {1, 2, 3, 'n'} 199 a_dictionary = {'key': 'value'} 200 reality = src.functions.w_keyword_arguments( 201 # first_input=a_dictionary, 202 # last_input=a_set, 203 first_input=a_set, 204 last_input=a_dictionary, 205 ) 206 my_expectation = (a_set, a_dictionary) 207 self.assertEqual(reality, my_expectation) 208 209 210# Exceptions seenthe test passes.
w_keyword_argumentsandw_positional_argumentsare the same functions, they alwaysreturn first_input, last_inputTheir names are different
def w_positional_arguments(first_input, last_input): def w_keyword_arguments(first_input, last_input):The difference that matters in the tests is how I call the functions
I have to give the input in order when I use positional arguments
w_positional_arguments('first', 'last') return ('first', 'last')w_positional_arguments('last', 'first') return ('last', 'first')w_positional_arguments(0, 1) return (0, 1)w_positional_arguments((1, 2, 3, 'n'), [1, 2, 3, 'n']) return ((1, 2, 3, 'n'), [1, 2, 3, 'n'])w_keyword_arguments('last', 'first') return ('last', 'first')I can give the input in any order when I use keyword arguments because I use the names from the function definition when I call it
w_keyword_arguments( first_input='first', last_input='last', ) return ('first', 'last')w_keyword_arguments( last_input='last', first_input='first', ) return ('first', 'last')w_keyword_arguments(last_input=0, first_input=1,) return (1, 0)w_keyword_arguments( first_input={'key': 'value'}, last_input={1, 2, 3, 'n'}, ) return ({'key': 'value'}, {1, 2, 3, 'n'})
I add another assertion to show that the two functions are the same, by calling the
w_positional_argumentsfunction with keyword arguments198 a_set = {1, 2, 3, 'n'} 199 a_dictionary = {'key': 'value'} 200 reality = src.functions.w_keyword_arguments( 201 # first_input=a_dictionary, 202 # last_input=a_set, 203 first_input=a_set, 204 last_input=a_dictionary, 205 ) 206 my_expectation = (a_set, a_dictionary) 207 self.assertEqual(reality, my_expectation) 208 209 a_tuple = (1, 2, 3, 'n') 210 a_list = [1, 2, 3, 'n'] 211 reality = src.functions.w_positional_arguments( 212 first_input=a_tuple, 213 last_input=a_list, 214 ) 215 my_expectation = (a_list, a_tuple) 216 self.assertEqual(reality, my_expectation) 217 218 219# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ((1, 2, 3, 'n'), [1, 2, 3, 'n']) != ([1, 2, 3, 'n'], (1, 2, 3, 'n'))because these two calls are the same
src.functions.w_positional_arguments( first_input=a_tuple, last_input=a_list, ) src.functions.w_positional_arguments( a_tuple, a_list, )I change
realityto match myexpectation209 a_tuple = (1, 2, 3, 'n') 210 a_list = [1, 2, 3, 'n'] 211 reality = src.functions.w_positional_arguments( 212 # first_input=a_tuple, 213 # last_input=a_list, 214 first_input=a_list, 215 last_input=a_tuple, 216 ) 217 my_expectation = (a_list, a_tuple) 218 self.assertEqual(reality, my_expectation) 219 220 221# Exceptions seenthe test passes.
I remove the commented lines
163 def test_w_keyword_arguments(self): 164 first, last = 'first', 'last' 165 166 reality = src.functions.w_keyword_arguments( 167 first_input=first, last_input=last, 168 ) 169 my_expectation = (first, last) 170 self.assertEqual(reality, my_expectation) 171 172 reality = src.functions.w_keyword_arguments( 173 last_input=last, first_input=first, 174 ) 175 my_expectation = (first, last) 176 self.assertEqual(reality, my_expectation) 177 178 reality = src.functions.w_keyword_arguments( 179 last, first, 180 ) 181 my_expectation = (last, first) 182 self.assertEqual(reality, my_expectation) 183 184 zero, one = 0, 1 185 reality = src.functions.w_keyword_arguments( 186 last_input=zero, first_input=one, 187 ) 188 my_expectation = (one, zero) 189 self.assertEqual(reality, my_expectation) 190 191 a_set = {1, 2, 3, 'n'} 192 a_dictionary = {'key': 'value'} 193 reality = src.functions.w_keyword_arguments( 194 first_input=a_set, 195 last_input=a_dictionary, 196 ) 197 my_expectation = (a_set, a_dictionary) 198 self.assertEqual(reality, my_expectation) 199 200 a_tuple = (1, 2, 3, 'n') 201 a_list = [1, 2, 3, 'n'] 202 reality = src.functions.w_positional_arguments( 203 first_input=a_list, 204 last_input=a_tuple, 205 ) 206 my_expectation = (a_list, a_tuple) 207 self.assertEqual(reality, my_expectation) 208 209 210# Exceptions seenI add a git commit message in the other terminal
git commit --all --message \ 'add test_w_keyword_arguments'the terminal shows a summary of the changes then goes back to the command line.
test_w_args_and_kwargs
I can write functions that take both positional and keyword arguments, which is useful when I want some arguments to be required and some to be optional.
RED: make it fail
I go back to the terminal where the tests are running
I add a failing test to
test_functions.py200 a_tuple = (1, 2, 3, 'n') 201 a_list = [1, 2, 3, 'n'] 202 reality = src.functions.w_positional_arguments( 203 first_input=a_list, 204 last_input=a_tuple, 205 ) 206 my_expectation = (a_list, a_tuple) 207 self.assertEqual(reality, my_expectation) 208 209 def test_w_args_and_kwargs(self): 210 reality = ( 211 src.functions.w_args_and_kwargs( 212 last_input='last', 'first', 213 ) 214 ) 215 my_expectation = ('first', 'last') 216 self.assertEqual(reality, my_expectation) 217 218 219# Exceptions seenthe terminal is my friend, and shows SyntaxError
SyntaxError: positional argument follows keyword argumentbecause I cannot put keyword arguments before positional arguments. The Integrated Development Environment (IDE) also shows the error with a red squiggly line under
'first'.
GREEN: make it pass
I add SyntaxError to the list of Exceptions seen, in
test_functions.py217# Exceptions seen 218# AssertionError 219# NameError 220# AttributeError 221# TypeError 222# SyntaxErrorI change the order of the arguments to follow Python rules
209 def test_w_args_and_kwargs(self): 210 reality = ( 211 src.functions.w_args_and_kwargs( 212 # last_input='last', 'first', 213 'first', last_input='last', 214 ) 215 ) 216 my_expectation = ('first', 'last') 217 self.assertEqual(reality, my_expectation) 218 219 220# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_args_and_kwargs'because
functions.pydoes not have anything namedw_args_and_kwargsI add a function to
functions.py30def w_keyword_arguments(first_input, last_input): 31 return first_input, last_input 32 33 34def w_args_and_kwargs(): 35 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_args_and_kwargs() got an unexpected keyword argument 'last_input'because the definition for
w_args_and_kwargsdoes not allow inputs and the test called the function with a keyword argument (last_input)I add the name to the function definition in parentheses, in
functions.py34# def w_args_and_kwargs(): 35def w_args_and_kwargs(last_input): 36 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_args_and_kwargs() got multiple values for argument 'last_input'because the definition for
w_args_and_kwargstakes one argument, and the test calls the function with two arguments('first', last_input='last'). How does Python know which value to use forlast_inputif I use the position and the keyword?I add another name in parentheses to make it clearer
34# def w_args_and_kwargs(): 35# def w_args_and_kwargs(last_input): 36def w_args_and_kwargs(last_input, first_input): 37 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_args_and_kwargs() got multiple values for argument 'last_input'because I have not fixed the problem, I gave confusing values in the call. Python still cannot tell the difference between the two values because I gave a positional value which according to the function definition is
last_inputand I gave a value with the namelast_input.How does it know what value to use for
last_input? The call tells it that the values forlast_inputare both'first'and'last', it would be like defining the function with the same name twice34# def w_args_and_kwargs(): 35# def w_args_and_kwargs(last_input): 36# def w_args_and_kwargs(last_input, first_input): 37def w_args_and_kwargs(last_input, last_input): 38 return Nonethe terminal is my friend, and shows SyntaxError
SyntaxError: duplicate argument 'last_input' in function definitionI change the names back and put them in the right order
34# def w_args_and_kwargs(): 35# def w_args_and_kwargs(last_input): 36# def w_args_and_kwargs(last_input, first_input): 37# def w_args_and_kwargs(last_input, last_input): 38def w_args_and_kwargs(first_input, last_input): 39 return Nonethe terminal is my friend, and shows AssertionError
AssertionError: None != ('first', 'last')because the function returns None and the assertion expects
('first', 'last')I change the return statement to give the test what it wants
34def w_args_and_kwargs(first_input, last_input): 35 return first_input, last_inputthe test passes.
I remove the commented lines
30def w_keyword_arguments(first_input, last_input): 31 return first_input, last_input 32 33 34def w_args_and_kwargs(first_input, last_input): 35 return first_input, last_inputI add variables to use them to remove the repetition of
'first'and'last'from test_w_args_and_kwargs intest_functions.py209 def test_w_args_and_kwargs(self): 210 first, last = 'first', 'last' 211 reality = ( 212 src.functions.w_args_and_kwargs( 213 # last_input='last', 'first', 214 'first', last_input='last', 215 ) 216 ) 217 my_expectation = ('first', 'last') 218 self.assertEqual(reality, my_expectation) 219 220 221# Exceptions seenI use the new variables to remove repetition of
'first'and'last'209 def test_w_args_and_kwargs(self): 210 first, last = 'first', 'last' 211 reality = ( 212 src.functions.w_args_and_kwargs( 213 # last_input='last', 'first', 214 # 'first', last_input='last', 215 first, last_input=last, 216 ) 217 ) 218 # my_expectation = ('first', 'last') 219 my_expectation = (first, last) 220 self.assertEqual(reality, my_expectation) 221 222 223# Exceptions seenthe test is still green.
I remove the commented lines
209 def test_w_args_and_kwargs(self): 210 first, last = 'first', 'last' 211 reality = ( 212 src.functions.w_args_and_kwargs( 213 first, last_input=last, 214 ) 215 ) 216 my_expectation = (first, last) 217 self.assertEqual(reality, my_expectation) 218 219 220# Exceptions seenI add a git commit message in the other terminal
git commit --all --message \ 'add test_w_args_and_kwargs'the terminal shows a summary of the changes then goes back to the command line.
test_w_optional_arguments
I can use positional and keyword arguments when I want some arguments to be required and some to be optional.
RED: make it fail
I go back to the terminal where the tests are running
I add a failing test to
test_functions.py209 def test_w_args_and_kwargs(self): 210 first, last = 'first', 'last' 211 reality = ( 212 src.functions.w_args_and_kwargs( 213 first, last_input=last, 214 ) 215 ) 216 my_expectation = (first, last) 217 self.assertEqual(reality, my_expectation) 218 219 def test_w_optional_arguments(self): 220 first_name, last_name = 'jane', 'doe' 221 reality = src.functions.w_optional_arguments( 222 first_name, last_input=last_name, 223 ) 224 my_expectation = (first_name, last_name) 225 self.assertEqual(reality, my_expectation) 226 227 228# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_optional_arguments'. Did you mean: 'w_positional_arguments'?because
functions.pydoes not have a definition forw_optional_arguments
GREEN: make it pass
I add a function named w_optional_arguments to functions.py
34 def w_args_and_kwargs(first_input, last_input):
35 return first_input, last_input
36
37
38 def w_optional_arguments(first_input, last_input):
39 return first_input, last_input
the test passes.
REFACTOR: make it better
I remove
last_input=last_namefrom the call tow_optional_argumentsintest_functions.py219 def test_w_optional_arguments(self): 220 first_name, last_name = 'jane', 'doe' 221 reality = src.functions.w_optional_arguments( 222 # first_name, last_input=last_name, 223 first_name, 224 ) 225 my_expectation = (first_name, last_name) 226 self.assertEqual(reality, my_expectation) 227 228 229# Exceptions seenthe terminal is my friend, and shows TypeError
TypeError: w_optional_arguments() missing 1 required positional argument: 'last_input'because the
last_inputargument MUST be given when this function is called (it is required).I make the argument optional by giving it a default value in
functions.py38# def w_optional_arguments(first_input, last_input): 39def w_optional_arguments(first_input, last_input='doe'): 40 return first_input, last_inputthe test passes since I do not need to give a value for the
last_inputparameter in the call tosrc.functions.w_optional_argumentsbecause the default value for thelast_inputparameter of the function isdoe. This means thatsrc.functions.w_optional_arguments('jane')is the same as
src.functions.w_optional_arguments('jane', last_input='doe')is the same as
return 'jane', 'doe'because
w_optional_argumentswill alwaysreturn first_input, last_inputA function uses the default value for a parameter when it is called without the parameter.
I remove the commented lines
I add another assertion to show that I can still call the function with different values, in test_w_optional_arguments in
test_functions.py219 def test_w_optional_arguments(self): 220 first_name, last_name = 'jane', 'doe' 221 reality = src.functions.w_optional_arguments( 222 # first_name, last_input=last_name, 223 first_name, 224 ) 225 my_expectation = (first_name, last_name) 226 self.assertEqual(reality, my_expectation) 227 228 first_name, blow = 'joe', 'blow' 229 reality = src.functions.w_optional_arguments( 230 first_name, blow, 231 ) 232 my_expectation = () 233 self.assertEqual(reality, my_expectation) 234 235 236# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('joe', 'blow') != ()I change
my_expectationto matchreality228 first_name, blow = 'joe', 'blow' 229 reality = src.functions.w_optional_arguments( 230 first_name, blow, 231 ) 232 # my_expectation = () 233 my_expectation = (first_name, blow) 234 self.assertEqual(reality, my_expectation) 235 236 237# Exceptions seenthe test passes.
I add another assertion
228 first_name, blow = 'joe', 'blow' 229 reality = src.functions.w_optional_arguments( 230 first_name, blow, 231 ) 232 # my_expectation = () 233 my_expectation = (first_name, blow) 234 self.assertEqual(reality, my_expectation) 235 236 first_name = 'john' 237 reality = src.functions.w_optional_arguments( 238 first_input=first_name, 239 ) 240 my_expectation = () 241 self.assertEqual(reality, my_expectation) 242 243 244# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('john', 'doe') != ()I change
my_expectationto matchreality236 first_name = 'john' 237 reality = src.functions.w_optional_arguments( 238 first_input=first_name, 239 ) 240 # my_expectation = () 241 my_expectation = (first_name, last_name) 242 self.assertEqual(reality, my_expectation) 243 244 245# Exceptions seenthe test passes since I do not need to give a value for the
last_inputparameter in the call tosrc.functions.w_optional_argumentsbecause the default value for thelast_inputparameter of thew_optional_argumentsfunction isdoe. This means thatsrc.functions.w_optional_arguments(first_input='john')is the same as
src.functions.w_optional_arguments( first_input='john', last_input='doe', )is the same as
return 'john', 'doe'because
w_optional_argumentswill alwaysreturn first_input, last_inputA function uses the default value for a parameter when it is called without the parameter.
I add one more assertion
236 first_name = 'john' 237 reality = src.functions.w_optional_arguments( 238 first_input=first_name, 239 ) 240 # my_expectation = () 241 my_expectation = (first_name, last_name) 242 self.assertEqual(reality, my_expectation) 243 244 last_name = 'smith' 245 reality = src.functions.w_optional_arguments( 246 last_input=last_name, 247 first_input=first_name, 248 ) 249 my_expectation = (last_name, first_name) 250 self.assertEqual(reality, my_expectation) 251 252 253# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ('john', 'smith') != ('smith', 'john')I change
my_expectationto matchreality244 last_name = 'smith' 245 reality = src.functions.w_optional_arguments( 246 last_input=last_name, 247 first_input=first_name, 248 ) 249 # my_expectation = (last_name, first_name) 250 my_expectation = (first_name, last_name) 251 self.assertEqual(reality, my_expectation) 252 253 254# Exceptions seenthe test passes.
I remove the commented lines
219 def test_w_optional_arguments(self): 220 first_name, last_name = 'jane', 'doe' 221 reality = src.functions.w_optional_arguments( 222 first_name, 223 ) 224 my_expectation = (first_name, last_name) 225 self.assertEqual(reality, my_expectation) 226 227 first_name, blow = 'joe', 'blow' 228 reality = src.functions.w_optional_arguments( 229 first_name, blow, 230 ) 231 my_expectation = (first_name, blow) 232 self.assertEqual(reality, my_expectation) 233 234 first_name = 'john' 235 reality = src.functions.w_optional_arguments( 236 first_input=first_name, 237 ) 238 my_expectation = (first_name, last_name) 239 self.assertEqual(reality, my_expectation) 240 241 last_name = 'smith' 242 reality = src.functions.w_optional_arguments( 243 last_input=last_name, 244 first_input=first_name, 245 ) 246 my_expectation = (first_name, last_name) 247 self.assertEqual(reality, my_expectation) 248 249 250# Exceptions seenI add a git commit message in the other terminal
git commit --all --message \ 'add test_w_optional_arguments'the terminal shows a summary of the changes then goes back to the command line.
Note
these four functions
w_keyword_argumentsw_positional_argumentsw_args_and_kwargsw_optional_arguments
are the same, they always return first_input, last_input, their names are different.
def w_positional_arguments(first_input, last_input):
def w_keyword_arguments(first_input, last_input):
def w_args_and_kwargs(first_input, last_input):
def w_optional_arguments(first_input, last_input='doe'):
first_input and last_input are also names (variables), they can be any names. The difference that matters in the tests is how I call the functions
w_positional_arguments('first', 'last')
return 'first', 'last'
w_positional_arguments('last', 'first')
return 'last', 'first'
w_positional_arguments(
first_input=[1, 2, 3, 'n'], last_input=(1, 2, 3, 'n')
)
return [1, 2, 3, 'n'], (1, 2, 3, 'n')
w_keyword_arguments(first_input='first', last_input='last')
return 'first', 'last'
w_keyword_arguments(last_input='last', first_input='first')
return 'first', 'last'
w_keyword_arguments('last', 'first')
return 'last', 'first'
w_args_and_kwargs('first', last_input='last')
return 'first', 'last'
w_optional_arguments('jane', last_input='doe')
return 'jane', 'doe'
w_optional_arguments('jane')
return 'jane', 'doe'
w_optional_arguments('joe', 'blow')
return 'joe', 'blow'
w_optional_arguments(
first_input='john', last_input='smith'
)
return 'john', 'smith'
Tip
as a rule of thumb I use keyword arguments when I have 2 or more inputs so I do not have to remember the order.
test_w_unknown_arguments
I can make functions that take any number of positional and keyword arguments. This means I do not need to know how many inputs the function should take when it is called.
RED: make it fail
I go back to the terminal where the tests are running
I add a new test to
test_functions.py241 last_name = 'smith' 242 reality = src.functions.w_optional_arguments( 243 last_input=last_name, 244 first_input=first_name, 245 ) 246 my_expectation = (first_name, last_name) 247 self.assertEqual(reality, my_expectation) 248 249 def test_w_unknown_arguments(self): 250 reality = src.functions.w_unknown_arguments( 251 0, 1, a=2, b=3, 252 ) 253 my_expectation = None 254 self.assertEqual(reality, my_expectation) 255 256 257# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.functions' has no attribute 'w_unknown_arguments'. Did you mean: 'w_keyword_arguments'?because
functions.pydoes not havew_unknown_arguments
GREEN: make it pass
I add the function to
functions.py38def w_optional_arguments(first_input, last_input='doe'): 39 return first_input, last_input 40 41 42def w_unknown_arguments(): 43 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_unknown_arguments() got an unexpected keyword argument 'a'I add the name to the function definition
42# def w_unknown_arguments(): 43def w_unknown_arguments(a): 44 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_unknown_arguments() got multiple values for argument 'a'I had this same problem in test_w_args_and_kwargs. Python cannot tell if
ais a positional or keyword argument based on my function definition.
double starred expressions
Python has a way for a function to take any number of keyword arguments without knowing how many they are. I use it to replace
ain the parentheses42# def w_unknown_arguments(): 43# def w_unknown_arguments(a): 44def w_unknown_arguments(**kwargs): 45 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_unknown_arguments() takes 0 positional arguments but 2 were givenI add a name for the first positional argument
42# def w_unknown_arguments(): 43# def w_unknown_arguments(a): 44# def w_unknown_arguments(**kwargs): 45def w_unknown_arguments(**kwargs, x): 46 return Nonethe terminal is my friend, and shows SyntaxError
SyntaxError: arguments cannot follow var-keyword argumenta reminder that I cannot put positional arguments after keyword arguments
I change the order of the inputs in
w_unknown_argumentsinfunctions.py42# def w_unknown_arguments(): 43# def w_unknown_arguments(a): 44# def w_unknown_arguments(**kwargs): 45# def w_unknown_arguments(**kwargs, x): 46def w_unknown_arguments(x, **kwargs): 47 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_unknown_arguments() takes 1 positional argument but 4 were givenI add a name for the other positional argument
42# def w_unknown_arguments(): 43# def w_unknown_arguments(a): 44# def w_unknown_arguments(**kwargs): 45# def w_unknown_arguments(**kwargs, x): 46# def w_unknown_arguments(x, **kwargs): 47def w_unknown_arguments(x, y, **kwargs): 48 return Nonethe test passes.
REFACTOR: make it better
I add an assertion to see what happens if I call the function with 3 keyword arguments
249 def test_w_unknown_arguments(self): 250 reality = src.functions.w_unknown_arguments( 251 0, 1, a=2, b=3, 252 ) 253 my_expectation = None 254 self.assertEqual(reality, my_expectation) 255 256 reality = src.functions.w_unknown_arguments( 257 0, 1, a=2, b=3, c=4, 258 ) 259 my_expectation = () 260 self.assertEqual(reality, my_expectation) 261 262 263# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: None != ()I change
my_expectationto matchreality256 reality = src.functions.w_unknown_arguments( 257 0, 1, a=2, b=3, c=4, 258 ) 259 # my_expectation = () 260 my_expectation = None 261 self.assertEqual(reality, my_expectation) 262 263 264# Exceptions seenthe test passes because the function can take any number of keyword arguments without knowing how many are in the call.
I add an assertion to see what happens when I call the function with 3 positional arguments
206 reality = src.functions.w_unknown_arguments( 207 0, 1, a=2, b=3, c=4, 208 ) 209 my_expectation = None 210 self.assertEqual(reality, my_expectation) 211 212 reality = src.functions.w_unknown_arguments( 213 0, 1, 2, a=3, b=4, c=5, 214 ) 215 my_expectation = None 216 self.assertEqual(reality, my_expectation) 217 218 219# Exceptions seenthe terminal is my friend, and shows TypeError
TypeError: w_unknown_arguments() takes 2 positional arguments but 3 were giventhe function definition only allows two positional arguments
I change the definition of the
w_unknown_argumentsfunction to make it take three positional arguments42# def w_unknown_arguments(): 43# def w_unknown_arguments(a): 44# def w_unknown_arguments(**kwargs): 45# def w_unknown_arguments(**kwargs, x): 46# def w_unknown_arguments(x, **kwargs): 47# def w_unknown_arguments(x, y, **kwargs): 48def w_unknown_arguments(x, y, z, **kwargs): 49 return Nonethe terminal is my friend, and shows TypeError
TypeError: w_unknown_arguments() missing 1 required positional argument: 'z'because the previous assertion calls the function with two positional arguments and it now requires three.
starred expressions
Python also has a way to handle any number of positional arguments. I use it
42# def w_unknown_arguments(): 43# def w_unknown_arguments(a): 44# def w_unknown_arguments(**kwargs): 45# def w_unknown_arguments(**kwargs, x): 46# def w_unknown_arguments(x, **kwargs): 47# def w_unknown_arguments(x, y, **kwargs): 48# def w_unknown_arguments(x, y, z, **kwargs): 49def w_unknown_arguments(*args, **kwargs): 50 return Nonethe test passes.
*args, **kwargsis Python convention. I change the names to make it clearer42# def w_unknown_arguments(): 43# def w_unknown_arguments(a): 44# def w_unknown_arguments(**kwargs): 45# def w_unknown_arguments(**kwargs, x): 46# def w_unknown_arguments(x, **kwargs): 47# def w_unknown_arguments(x, y, **kwargs): 48# def w_unknown_arguments(x, y, z, **kwargs): 49# def w_unknown_arguments(*args, **kwargs): 50def w_unknown_arguments( 51 *positional_arguments, **keyword_arguments 52 ): 53 return NoneI change the return statement because I want the function to return its input (remember the identity function?)
50def w_unknown_arguments( 51 *positional_arguments, **keyword_arguments 52 ): 53 # return None 54 return positional_arguments, keyword_argumentsthe terminal is my friend, and shows
AssertionError: ((0, 1), {'a': 2, 'b': 3}) != NoneI get a tuple that has a tuple and a dictionary
I change
my_expectationto matchrealityin the first assertion249 def test_w_unknown_arguments(self): 250 reality = src.functions.w_unknown_arguments( 251 0, 1, a=2, b=3, 252 ) 253 # my_expectation = None 254 my_expectation = ((0, 1), {'a': 2, 'b': 3}) 255 self.assertEqual(reality, my_expectation)the terminal is my friend, and shows AssertionError
AssertionError: ((0, 1), {'a': 2, 'b': 3, 'c': 4}) != NoneI change
my_expectationto matchrealityin the second assertion249 def test_w_unknown_arguments(self): 250 reality = src.functions.w_unknown_arguments( 251 0, 1, a=2, b=3, 252 ) 253 # my_expectation = None 254 my_expectation = ((0, 1), {'a': 2, 'b': 3}) 255 self.assertEqual(reality, my_expectation) 256 257 reality = src.functions.w_unknown_arguments( 258 0, 1, a=2, b=3, c=4, 259 ) 260 # my_expectation = () 261 # my_expectation = None 262 my_expectation = ( 263 (0, 1), {'a': 2, 'b': 3, 'c': 4} 264 ) 265 self.assertEqual(reality, my_expectation)the terminal is my friend, and shows AssertionError
AssertionError: ((0, 1, 2), {'a': 3, 'b': 4, 'c': 5}) != NoneI change
my_expectationto matchrealityin the last assertion249 def test_w_unknown_arguments(self): 250 reality = src.functions.w_unknown_arguments( 251 0, 1, a=2, b=3, 252 ) 253 # my_expectation = None 254 my_expectation = ((0, 1), {'a': 2, 'b': 3}) 255 self.assertEqual(reality, my_expectation) 256 257 reality = src.functions.w_unknown_arguments( 258 0, 1, a=2, b=3, c=4, 259 ) 260 # my_expectation = () 261 # my_expectation = None 262 my_expectation = ( 263 (0, 1), {'a': 2, 'b': 3, 'c': 4} 264 ) 265 self.assertEqual(reality, my_expectation) 266 267 reality = src.functions.w_unknown_arguments( 268 0, 1, 2, a=3, b=4, c=5, 269 ) 270 # my_expectation = None 271 my_expectation = ( 272 (0, 1, 2), {'a': 3, 'b': 4, 'c': 5} 273 ) 274 self.assertEqual(reality, my_expectation) 275 276 277# Exceptions seenthe test passes.
I add variables to use them to remove repetition of the tuple and dictionary from the first assertion
249 def test_w_unknown_arguments(self): 250 a_tuple = (0, 1) 251 a_dictionary = {'a': 2, 'b': 3} 252 reality = src.functions.w_unknown_arguments( 253 0, 1, a=2, b=3, 254 ) 255 # my_expectation = None 256 my_expectation = ((0, 1), {'a': 2, 'b': 3}) 257 self.assertEqual(reality, my_expectation)I use the variables to remove repetition of the values
249 def test_w_unknown_arguments(self): 250 a_tuple = (0, 1) 251 a_dictionary = {'a': 2, 'b': 3} 252 reality = src.functions.w_unknown_arguments( 253 # 0, 1, a=2, b=3, 254 a_tuple, a_dictionary 255 ) 256 # my_expectation = None 257 # my_expectation = ((0, 1), {'a': 2, 'b': 3}) 258 my_expectation = (a_tuple, a_dictionary) 259 self.assertEqual(reality, my_expectation)the terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: (((0, 1), {'a': 2, 'b': 3}), {}) != ((0, 1), {'a': 2, 'b': 3})because passing in the values this way means I am sending in two positional arguments -
(a_tuple, a_dictionary)so I get a tuple with a tuple of the arguments and an empty dictionary instead of a tuple with the arguments in the tuple I sent and a dictionary with the dictionary I sentI change the inputs with
*and**so that Python breaks up the contents, allowing them to be used as separate arguments249 def test_w_unknown_arguments(self): 250 a_tuple = (0, 1) 251 a_dictionary = {'a': 2, 'b': 3} 252 reality = src.functions.w_unknown_arguments( 253 # 0, 1, a=2, b=3, 254 # a_tuple, a_dictionary 255 *a_tuple, **a_dictionary 256 ) 257 # my_expectation = None 258 # my_expectation = ((0, 1), {'a': 2, 'b': 3}) 259 my_expectation = (a_tuple, a_dictionary) 260 self.assertEqual(reality, my_expectation)the test passes because
src.functions.w_unknown_arguments(*a_tuple, **a_dictionary)issrc.functions.w_unknown_arguments(0, 1, a=2, b=3).I add variables to the next assertion to use them to remove repetition of the tuple and dictionary from the second assertion
249 def test_w_unknown_arguments(self): 250 a_tuple = (0, 1) 251 a_dictionary = {'a': 2, 'b': 3} 252 reality = src.functions.w_unknown_arguments( 253 # 0, 1, a=2, b=3, 254 # a_tuple, a_dictionary 255 *a_tuple, **a_dictionary 256 ) 257 # my_expectation = None 258 # my_expectation = ((0, 1), {'a': 2, 'b': 3}) 259 my_expectation = (a_tuple, a_dictionary) 260 self.assertEqual(reality, my_expectation) 261 262 a_tuple = (0, 1) 263 a_dictionary = {'a': 2, 'b': 3, 'c': 4} 264 reality = src.functions.w_unknown_arguments( 265 0, 1, a=2, b=3, c=4, 266 ) 267 # my_expectation = () 268 # my_expectation = None 269 my_expectation = ( 270 (0, 1), {'a': 2, 'b': 3, 'c': 4} 271 ) 272 self.assertEqual(reality, my_expectation)I use the variables to remove repetition of the tuple and dictionary
262 a_tuple = (0, 1) 263 a_dictionary = {'a': 2, 'b': 3, 'c': 4} 264 reality = src.functions.w_unknown_arguments( 265 # 0, 1, a=2, b=3, c=4, 266 a_tuple, a_dictionary 267 ) 268 # my_expectation = () 269 # my_expectation = None 270 my_expectation = ( 271 # (0, 1), {'a': 2, 'b': 3, 'c': 4} 272 a_tuple, a_dictionary 273 ) 274 self.assertEqual(reality, my_expectation)the terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: (((0, 1), {'a': 2, 'b': 3, 'c': 4}), {}) != ((0, 1), {'a': 2, 'b': 3, 'c': 4})because passing in the values this way means I am sending in two positional arguments -
(a_tuple, a_dictionary)so I get a tuple with a tuple of the arguments and an empty dictionary instead of a tuple with the arguments in the tuple I sent and a dictionary with the dictionary I sentI change the inputs with
*and**so that Python breaks up the contents, allowing them to be used as separate arguments262 a_tuple = (0, 1) 263 a_dictionary = {'a': 2, 'b': 3, 'c': 4} 264 reality = src.functions.w_unknown_arguments( 265 # 0, 1, a=2, b=3, c=4, 266 # a_tuple, a_dictionary 267 *a_tuple, **a_dictionary 268 ) 269 # my_expectation = () 270 # my_expectation = None 271 my_expectation = ( 272 # (0, 1), {'a': 2, 'b': 3, 'c': 4} 273 a_tuple, a_dictionary 274 ) 275 self.assertEqual(reality, my_expectation)the test passes because
src.functions.w_unknown_arguments(*a_tuple, **a_dictionary)issrc.functions.w_unknown_arguments(0, 1, a=2, b=3, c=4).I add variables to the third assertion to use them to remove repetition of the tuple and dictionary
249 def test_w_unknown_arguments(self): 250 a_tuple = (0, 1) 251 a_dictionary = {'a': 2, 'b': 3} 252 reality = src.functions.w_unknown_arguments( 253 # 0, 1, a=2, b=3, 254 # a_tuple, a_dictionary 255 *a_tuple, **a_dictionary 256 ) 257 # my_expectation = None 258 # my_expectation = ((0, 1), {'a': 2, 'b': 3}) 259 my_expectation = (a_tuple, a_dictionary) 260 self.assertEqual(reality, my_expectation) 261 262 a_tuple = (0, 1) 263 a_dictionary = {'a': 2, 'b': 3, 'c': 4} 264 reality = src.functions.w_unknown_arguments( 265 # 0, 1, a=2, b=3, c=4, 266 # a_tuple, a_dictionary 267 *a_tuple, **a_dictionary 268 ) 269 # my_expectation = () 270 # my_expectation = None 271 my_expectation = ( 272 # (0, 1), {'a': 2, 'b': 3, 'c': 4} 273 a_tuple, a_dictionary 274 ) 275 self.assertEqual(reality, my_expectation) 276 277 a_tuple = (0, 1, 2) 278 a_dictionary = {'a': 3, 'b': 4, 'c': 5} 279 reality = src.functions.w_unknown_arguments( 280 0, 1, 2, a=3, b=4, c=5, 281 ) 282 # my_expectation = None 283 my_expectation = ( 284 (0, 1, 2), {'a': 3, 'b': 4, 'c': 5} 285 ) 286 self.assertEqual(reality, my_expectation) 287 288 289# Exceptions seenI use the variables to remove repetition of the tuple and dictionary
277 a_tuple = (0, 1, 2) 278 a_dictionary = {'a': 3, 'b': 4, 'c': 5} 279 reality = src.functions.w_unknown_arguments( 280 # 0, 1, 2, a=3, b=4, c=5, 281 a_tuple, a_dictionary, 282 ) 283 # my_expectation = None 284 my_expectation = ( 285 # (0, 1, 2), {'a': 3, 'b': 4, 'c': 5} 286 a_tuple, a_dictionary 287 ) 288 self.assertEqual(reality, my_expectation) 289 290 291# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: (((0, 1, 2), {'a': 3, 'b': 4, 'c': 5}), {}) != ((0, 1, 2), {'a': 3, 'b': 4, 'c': 5})because passing in the values this way means I am sending in two positional arguments -
(a_tuple, a_dictionary)so I get a tuple with a tuple of the arguments and an empty dictionary instead of a tuple with the arguments in the tuple I sent and a dictionary with the dictionary I sentI change the inputs with
*and**so that Python breaks up the contents, allowing them to be used as separate arguments277 a_tuple = (0, 1, 2) 278 a_dictionary = {'a': 3, 'b': 4, 'c': 5} 279 reality = src.functions.w_unknown_arguments( 280 # 0, 1, 2, a=3, b=4, c=5, 281 # a_tuple, a_dictionary, 282 *a_tuple, **a_dictionary, 283 ) 284 # my_expectation = None 285 my_expectation = ( 286 # (0, 1, 2), {'a': 3, 'b': 4, 'c': 5} 287 a_tuple, a_dictionary 288 ) 289 self.assertEqual(reality, my_expectation) 290 291 292# Exceptions seenthe test passes because
src.functions.w_unknown_arguments(*a_tuple, **a_dictionary)issrc.functions.w_unknown_arguments(0, 1, 2, a=3, b=4, c=5).
how Python reads positional arguments
I add an assertion to see what happens when I call w_unknown_arguments with ONLY positional arguments.
277 a_tuple = (0, 1, 2)
278 a_dictionary = {'a': 3, 'b': 4, 'c': 5}
279 reality = src.functions.w_unknown_arguments(
280 # 0, 1, 2, a=3, b=4, c=5,
281 # a_tuple, a_dictionary,
282 *a_tuple, **a_dictionary,
283 )
284 # my_expectation = None
285 my_expectation = (
286 # (0, 1, 2), {'a': 3, 'b': 4, 'c': 5}
287 a_tuple, a_dictionary
288 )
289 self.assertEqual(reality, my_expectation)
290
291 a_tuple = (0, 1, 2, 3)
292 reality = src.functions.w_unknown_arguments(
293 *a_tuple
294 )
295 my_expectation = ()
296 self.assertEqual(reality, my_expectation)
297
298
299 # Exceptions seen
the terminal is my friend, and shows AssertionError
AssertionError: Tuples differ: ((0, 1, 2, 3), {}) != ()
I change my_expectation to match reality
291 a_tuple = (0, 1, 2, 3)
292 reality = src.functions.w_unknown_arguments(
293 *a_tuple
294 )
295 # my_expectation = ()
296 my_expectation = (a_tuple, {})
297 self.assertEqual(reality, my_expectation)
298
299
300 # Exceptions seen
the test passes. The function gives me back the positional arguments in a tuple (things in parentheses (()) separated by commas) and gives me an empty dictionary (any key-value pairs in curly braces { } separated by a comma) for the keyword arguments because I did not give any in the call.
how Python reads keyword arguments
I add another assertion to see what happens when I call the function with ONLY keyword arguments
291 a_tuple = (0, 1, 2, 3)
292 reality = src.functions.w_unknown_arguments(
293 *a_tuple
294 )
295 # my_expectation = ()
296 my_expectation = (a_tuple, {})
297 self.assertEqual(reality, my_expectation)
298
299 a_dictionary = {'a': 4, 'b': 5, 'c': 6, 'd': 7}
300 reality = src.functions.w_unknown_arguments(
301 **a_dictionary
302 )
303 my_expectation = ()
304 self.assertEqual(reality, my_expectation)
305
306
307 # Exceptions seen
the terminal is my friend, and shows
AssertionError: Tuples differ:
((), {'a': 4, 'b': 5, 'c': 6, 'd': 7}) != ()
I change my_expectation to match reality
299 a_dictionary = {'a': 4, 'b': 5, 'c': 6, 'd': 7}
300 reality = src.functions.w_unknown_arguments(
301 **a_dictionary
302 )
303 # my_expectation = ()
304 my_expectation = ((), a_dictionary)
305 self.assertEqual(reality, my_expectation)
306
307
308 # Exceptions seen
the test passes. The function gives me back the positional arguments as an empty tuple (things in parentheses (()) separated by commas) because I did not give any in the call, it gives me a dictionary (any key-value pairs in curly braces { } separated by a comma) of the keyword arguments.
how Python reads positional and keyword arguments
I add one more assertion to see what happens when I call the function with no inputs
299 a_dictionary = {'a': 4, 'b': 5, 'c': 6, 'd': 7} 300 reality = src.functions.w_unknown_arguments( 301 **a_dictionary 302 ) 303 # my_expectation = () 304 my_expectation = ((), a_dictionary) 305 self.assertEqual(reality, my_expectation) 306 307 reality = src.functions.w_unknown_arguments() 308 my_expectation = TypeError 309 self.assertEqual(reality, my_expectation) 310 311 312# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: ((), {}) != <class 'TypeError'>I change the
my_expectationto matchreality307 reality = src.functions.w_unknown_arguments() 308 # my_expectation = TypeError 309 my_expectation = ((), {}) 310 self.assertEqual(reality, my_expectation) 311 312 313# Exceptions seenthe test passes.
I remove the commented lines
249 def test_w_unknown_arguments(self): 250 a_tuple = (0, 1) 251 a_dictionary = {'a': 2, 'b': 3} 252 reality = src.functions.w_unknown_arguments( 253 *a_tuple, **a_dictionary 254 ) 255 my_expectation = (a_tuple, a_dictionary) 256 self.assertEqual(reality, my_expectation) 257 258 a_tuple = (0, 1) 259 a_dictionary = {'a': 2, 'b': 3, 'c': 4} 260 reality = src.functions.w_unknown_arguments( 261 *a_tuple, **a_dictionary 262 ) 263 my_expectation = ( 264 a_tuple, a_dictionary 265 ) 266 self.assertEqual(reality, my_expectation) 267 268 a_tuple = (0, 1, 2) 269 a_dictionary = {'a': 3, 'b': 4, 'c': 5} 270 reality = src.functions.w_unknown_arguments( 271 *a_tuple, **a_dictionary, 272 ) 273 my_expectation = ( 274 a_tuple, a_dictionary 275 ) 276 self.assertEqual(reality, my_expectation) 277 278 a_tuple = (0, 1, 2, 3) 279 reality = src.functions.w_unknown_arguments( 280 *a_tuple 281 ) 282 my_expectation = (a_tuple, {}) 283 self.assertEqual(reality, my_expectation) 284 285 a_dictionary = {'a': 4, 'b': 5, 'c': 6, 'd': 7} 286 reality = src.functions.w_unknown_arguments( 287 **a_dictionary 288 ) 289 my_expectation = ((), a_dictionary) 290 self.assertEqual(reality, my_expectation) 291 292 reality = src.functions.w_unknown_arguments() 293 my_expectation = ((), {}) 294 self.assertEqual(reality, my_expectation) 295 296 297# Exceptions seenI remove the commented lines from the w_unknown_arguments function in
functions.py38def w_optional_arguments(first_input, last_input='doe'): 39 return first_input, last_input 40 41 42def w_unknown_arguments( 43 *positional_arguments, **keyword_arguments 44 ): 45 return positional_arguments, keyword_argumentsI add a git commit message in the other terminal
git commit --all --message \ 'add test_w_unknown_arguments'the terminal shows a summary of the changes then goes back to the command line.
Note
these statements are the same
w_unknown_arguments(0, 1, 2, 3, a=4, b=5, c=6, d=7)
w_unknown_arguments(
*(0, 1, 2, 3), **{'a': 4, 'b': 5, 'c': 6, 'd': 7}
)
because w_unknown_arguments in functions.py in the src folder will always
return positional_arguments, keyword_arguments
in this case
0, 1, 2, 3
*(0, 1, 2, 3)
are positional arguments which are taken as a tuple and
a=4, b=5, c=6, d=7
**{'a': 4, 'b': 5, 'c': 6, 'd': 7}
are keyword arguments which are taken as a dictionary.
The function reads positional arguments as tuples, and keyword arguments as dictionaries.
Is this why the update method of dictionaries can take a dictionary as input?
close the project
I close
test_functions.pyandfunctions.pyI click in the terminal where the tests are running
I use q on the keyboard to leave the tests. The terminal goes back to the command line.
I change directory to the parent of
functionscd ..the terminal shows
.../pumping_pythonI am back in the
pumping_pythondirectory
review
I ran tests to show that I can make functions with
the def keyword
as a reminder
code from the chapter
what is next?
you have covered a bit so far and know
Optional continuations in the same functions project (after you know classes and AssertionError 2):
Functions 2: use class attributes - remove repetition of literal values in
test_w_positional_arguments,test_w_keyword_argumentsandtest_w_args_and_kwargsby using class attributes onTestFunctions(no setUp needed for these constants)functions 3 - use for loops (and list comprehensions) to DRY the repetitive
test_why_use_a_function
Would you like to test how to pass values from tests to functions with assert methods?
rate pumping python
If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too.