You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You should now have a version of the mailroom program that has complete tests for all the logic code.
8
+
That is: every function in mailroom that does not contain a ``print`` or ``input`` call should be tested.
9
+
10
+
And, critically: every function that contains a ``print`` or ``input`` should contain *no other logic at all*.
11
+
12
+
But now you've learned about more advanced techniques, like mocking and parameterized tests, so you should be able get your mailroom tests to 100% coverage -- and maybe even make the tests more efficient and complete with some other techniques.
13
+
14
+
The Task
15
+
--------
16
+
17
+
Use mocking of the ``input()`` function to write a full set of tests for the interactive portion of your mailroom program.
18
+
19
+
Then run ``coverage`` and make sure everything is covered -- if not, then find those holes and fill them. You should be able to provide a report indicating 100% coverage.
Copy file name to clipboardExpand all lines: source/modules/Closures.rst
+25-6Lines changed: 25 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,18 +6,29 @@ Closures and Function Currying
6
6
7
7
Defining specialized functions on the fly.
8
8
9
+
A "Closure" is a fancy CS term that can be very hard to understand. Partly because they are expressed a little differently in every computer language that supports them But this is easiest definition I could find:
10
+
11
+
Closure is when a function “remembers” its lexical scope even when the function is executed outside that lexical scope
12
+
13
+
This definition is provided by Kyle Simpson
14
+
(by way of `an article about closures in Javascript <https://medium.com/beginners-guide-to-mobile-web-development/closures-in-functional-programming-and-javascript-3ed730e08fc2>`_).
15
+
16
+
The basic idea behind the concept of a closure lies in the understanding of the fact that closure is a mechanism by which an inner function will have access to the variables defined in its outer function’s lexical scope even after the outer function has returned.
17
+
18
+
Which brings us to the key practical part of how this works in Python:
19
+
9
20
10
21
Scope
11
22
=====
12
23
13
24
In order to get a handle on all this, it's important to understand variable scoping rules in Python.
14
25
15
-
"Scope" is the word for where the names in your code are accessible. Another word for a scope is namespace.
26
+
"Scope" is the word for `where` the names in your code are accessible. Another word for a scope is namespace.
16
27
17
28
Global Scope
18
29
------------
19
30
20
-
The simplest is the global scope. This is where all the names defined right in your code file (module) are. When running in an interactavive interpreter, it is in the global namespace as well.
31
+
The simplest is the global scope. This is where all the names defined right in your code file (module) are. When running in an interactive interpreter, it is in the global namespace as well.
21
32
22
33
You can get the global namespace with the ``globals()`` function, but ...
23
34
@@ -79,6 +90,9 @@ names are created by assignment, and by ``def`` and ``class`` statements. We alr
79
90
test
80
91
TestClass
81
92
93
+
Always keep in mind that in Python, "global" means "global to the module", *not* global to the entire program. In the case of the interactive interpreter, the module is the "__main__" module (remember ``if __name__ == __main__:``?). But in a particular python file (usually one file is one module), the global scope is global to that one file.
94
+
95
+
82
96
Local Scope
83
97
-----------
84
98
@@ -188,7 +202,7 @@ But any names not defined in an inner scope will be found by looking in the encl
188
202
this is in outer
189
203
this is in inner
190
204
191
-
Look carefully to see where each of those names came from. All the print statements are in the inner function, so its local scope is searched first, and then the outer function's scope, and then the global scope. ``name1`` is only defined in the global scope, so that one is found.
205
+
Look carefully to see where each of those names came from. All the print statements are in the inner function, so its local scope is searched first, and then the outer function's scope, and then the global scope. ``name1`` is only defined in the global scope, so that one is found. but ``name2`` is redfined in the scope of the ``outer`` function, so that one is found. And ``name3`` is only defined in the ``inner`` function scope.
192
206
193
207
The ``global`` keyword
194
208
----------------------
@@ -218,6 +232,8 @@ Global names can be accessed from within functions, but not if that same name is
218
232
219
233
The problem here is that ``x += 5`` is the same as ``x = x + 5``, so it is creating a local name, but it can't be incremented, because it hasn't had a value set yet.
220
234
235
+
How does the interpreter know that ``x`` is a local name? When it compiles the function definition, it marks all the names assigned in the function as local. So when the function runs, it knows that ``x`` is local, and thus it won't go look in the global scope for it.
236
+
221
237
The ``global`` keyword tells python that you want to use the global name, rather than create a new, local name:
222
238
223
239
.. code-block:: ipython
@@ -233,12 +249,13 @@ The ``global`` keyword tells python that you want to use the global name, rather
233
249
In [42]: x
234
250
Out[42]: 10
235
251
236
-
**NOTE:** The use of ``global`` is frowned upon -- having global variables manipulated in arbitrary other scopes makes for buggy, hard to maintain code!
252
+
**NOTE:** The use of ``global`` is frowned upon -- having global variables manipulated in arbitrary other scopes makes for buggy, hard to maintain code! You hardly ever need to use ``global`` -- if a function needs to manipulate a value, you should pass that value into the function, or have it return a value that can then be used to change the global name.
253
+
237
254
238
255
``nonlocal`` keyword
239
256
--------------------
240
257
241
-
The other limitation with ``global`` is that there is only one global namespace, so what if you are in a nested scope, and want to get at the value outside the current scope, but not all the way up at the global scope:
258
+
The other limitation with ``global`` is that there is only one global namespace. What if you are in a nested scope, and want to get at the value outside the current scope, but not all the way up at the global scope:
242
259
243
260
.. code-block:: ipython
244
261
@@ -285,7 +302,8 @@ But if we use ``global``, we'll get the global ``x``:
285
302
286
303
This indicates that the global ``x`` is getting changed, but not the one in the ``outer`` scope.
287
304
288
-
This is enough of a limitation that Python 3 added a new keyword: ``nonlocal``. What it means is that the name should be looked for outside the local scope, but only as far as you need to go to find it:
305
+
This is enough of a limitation that Python 3 added a new keyword: ``nonlocal``.
306
+
What it means is that the name should be looked for outside the local scope, but only as far as you need to go to find it:
289
307
290
308
.. code-block:: ipython
291
309
@@ -337,6 +355,7 @@ But it will go up multiple levels in nested scopes:
0 commit comments