-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy path2_programs_in_files.html
More file actions
1035 lines (998 loc) · 91 KB
/
2_programs_in_files.html
File metadata and controls
1035 lines (998 loc) · 91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en" data-content_root="./">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>2. Programs in files — Object-oriented Programming documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=03e43079" />
<link rel="stylesheet" type="text/css" href="_static/fenics.css?v=8c7d05f9" />
<link rel="stylesheet" type="text/css" href="_static/proof.css" />
<link rel="stylesheet" type="text/css" href="_static/graphviz.css?v=fd3f3429" />
<script src="_static/documentation_options.js?v=5929fcd5"></script>
<script src="_static/doctools.js?v=9a2dae69"></script>
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="_static/proof.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="3. Objects and abstraction" href="3_objects.html" />
<link rel="prev" title="1. Introduction: abstraction in mathematics and programming" href="1_introduction.html" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="_static/ie6.css" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-0EFVH5C4DC"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-0EFVH5C4DC');
</script>
<link rel="stylesheet" href="_static/featured.css">
<link rel="shortcut icon" href="_static/icon.ico" />
</head><body>
<div class="wrapper">
<a href="index.html"><img src="_static/banner.png" width="900px" alt="FInAT Project Banner" /></a>
<div id="access">
<div class="menu">
<ul>
<li class="page_item"><a href="index.html" title="Book">Book</a></li>
<li class="page_item"><a href="videos.html" title="Videos">Videos</a></li>
<li class="page_item"><a href="exercises.html"
title="Exercises">Exercises</a></li>
<li class="page_item"><a href="installation.html" title="Installation">Installation</a></li>
</ul>
</div><!-- .menu -->
</div><!-- #access -->
</div><!-- #wrapper -->
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="programs-in-files">
<span id="programs-files"></span><h1><span class="section-number">2. </span>Programs in files<a class="headerlink" href="#programs-in-files" title="Link to this heading">¶</a></h1>
<p>In this chapter we will start to learn how to combine pieces of code into
larger units, and how to package up your code so that you or others can do the
same. You may previously have written Python code in Jupyter notebooks, and
possibly used an interactive Python environment such as IPython. Jupyter
notebooks are an excellent platform for writing and documenting short pieces of
code. However, they are much less good for writing code which is designed to be
used by other people. If the intention is to write mathematical building blocks
out of which more complex algorithms can be constructed, then we need a
different way of storing code: one which is accessible in more automated ways
than typing in a web browser. As an introduction to writing code in files, we
will first consider Python scripts. We’ll then move on to making code really
reusable by creating Python modules and packages.</p>
<section id="the-python-interpreter">
<h2><span class="section-number">2.1. </span>The Python interpreter<a class="headerlink" href="#the-python-interpreter" title="Link to this heading">¶</a></h2>
<details>
<summary>
Video: a first Python script.</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/486557682" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=8773e5b7-a331-4ca3-a59d-ae1c00da3b4f">watch this video on Panopto</a></p>
</details><p>Before we dive into the various different ways that Python code can be
organised and run, it’s helpful to have a mental model of what it actually
means for Python code to execute. Python is an interpreted language. This means
that the program that runs is not made up of the primitive machine-level
instructions that the processor in your computer executes. Instead, the Python
program is read and executed by another piece of software, the Python
interpreter. The Python interpreter takes a sequence of Python statements and
performs the actions they specify. The interpreter takes care of allocating the
required memory and causes the right sequences of primitive machine-level
instructions to execute on the actual hardware such that your programme runs.</p>
<p>The Python interpreter is the same no matter whether you use Jupyter
notebooks, an interactive Python terminal such as IPython, or execute
code written in Python scripts. These are all just different ways of
providing a sequence of Python commands to the interpreter, and
conveying the output back to the user. This means that the same Python
code works in essentially the same way no matter how you use
Python. The Python interpreter also sits between the Python code and
the operating system, so for most purposes, it also doesn’t matter
whether your Python program is running on Windows, macOS, Linux, or
maybe something more exotic. Usually, when we refer to Python doing
something or responding to code in a particular way, what we mean is
that this is what the interpreter does in those circumstances.</p>
<section id="ipython">
<h3><span class="section-number">2.1.1. </span>IPython<a class="headerlink" href="#ipython" title="Link to this heading">¶</a></h3>
<p>If you’ve only ever used Jupyter notebooks, then you won’t yet have encountered
a purely command line interface to the Python interpreter. You can launch a
command line Python interface simply by running the command <code class="xref py py-obj docutils literal notranslate"><span class="pre">python</span></code> with no
further arguments. However, a much more user-friendly interface with features
such as syntax highlighting, tab completion and a searchable command history is
provided by IPython. If you’re familiar with Jupyter notebooks then IPython
will be very familiar indeed, because the Python backend to Jupyter is IPython.</p>
<p>IPython is available as a package on PyPI. So, having ensured that our venv is
active, we can install it by running:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>ipython
</pre></div>
</div>
<p>IPython can now be run by simply typing:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>ipython
</pre></div>
</div>
<p>This will result in output similar to the following:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="go">Python 3.11.0 (main, Oct 25 2022, 14:13:24) [Clang 14.0.0 (clang-1400.0.29.202)]</span>
<span class="go">Type 'copyright', 'credits' or 'license' for more information</span>
<span class="go">IPython 8.6.0 -- An enhanced Interactive Python. Type '?' for help.</span>
<span class="gp">In [1]:</span>
</pre></div>
</div>
<p>Just as in a Jupyter notebook, this last line is the Python prompt at which
you can type any Python you like. If you press return after a complete Python
statement, the statement will execute immediately. Unlike in a Jupyter
notebook, there is no special key combination or button to trigger execution.
We’ll use IPython from time to time to illustrate the operation of the various
Python constructs that we’ll learn about. However, our focus is on building
larger units of code, and it is to this that we will now turn.</p>
</section>
</section>
<section id="python-scripts-and-text-editors">
<h2><span class="section-number">2.2. </span>Python scripts and text editors<a class="headerlink" href="#python-scripts-and-text-editors" title="Link to this heading">¶</a></h2>
<p>A Python script is simply a plain text file containing Python code. If
we pass the file to the Python interpreter, then all the code in the
file will be executed, it’s that simple. So, we need a way to create
files full of Python code, and a way to feed them to Python. We create
and edit Python files with a program called a text editor. A good text
editor will help you to code by highlighting syntax and helping with
indentation. Some text editors also feature advanced features such as
built-in access to documentation, or highlighting style problems in
your code. A more fully-featured option is an <a class="reference internal" href="1_introduction.html#term-integrated-development-environment"><span class="xref std std-term">integrated development
environment</span></a> (IDE). IDEs combine an editor with a Python interpreter to
run your code, a debugger and often other features such as integration
with Git.</p>
<p>One such IDE is Microsoft Visual Studio Code. This is a free and open source
IDE with good support for Git and Python, including for debugging Python
programmes. It also has a particularly helpful Live Share facility, which
enables two or more programmers to work on the same piece of code at the same
time over the internet. The descriptions presented here will assume that you
are using Visual Studio Code, but you can, of course, use another editor or IDE
for your Python programming.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Text files</p>
<p>You are doubtless familiar with the concept of a file stored in a folder on
your computer. You will also be aware that there are many different types
of file, more or less related to the type of data they contain and the
programs which created them. Files fall into two important categories,
binary files and text files. A binary file is a stream of data whose
contents make sense under the rules of the application which created it,
but not otherwise. Word documents, PDFs, and JPEGs are examples of binary
files. Plain text files are files which, as the name suggests, consist of a
string of characters. Anyone looking at the content of a text file can
understand it, so long as they understand the human or computer language in
which it is written. LaTeX source files and Python scripts are examples of
text files. This matters when you come to edit these files. Text files are
edited using a text editor, or an IDE. Usually you can use whichever text
editor you like, though some will have better support for writing some
computer languages than others. Importantly, you can’t edit text files in a
program such as Microsoft Word and expect to end up with something usable.</p>
</div>
<section id="setting-up-a-visual-studio-code-workspace">
<span id="workspaces"></span><h3><span class="section-number">2.2.1. </span>Setting up a Visual Studio Code workspace<a class="headerlink" href="#setting-up-a-visual-studio-code-workspace" title="Link to this heading">¶</a></h3>
<p>Over the course of this book, you will work in a number of git repositories,
each containing the exercises for one chapter. In order for Visual Studio Code
to correctly find all the configuration files you need it to, it’s helpful to
use what is called a <a class="reference external" href="https://code.visualstudio.com/docs/editor/multi-root-workspaces">Multi-root Workspace</a>. This is
simply a way of telling Visual Studio Code that we have multiple folders
containing code. Once we start using Visual Studio Code’s style checking
features in <a class="reference internal" href="4_style.html#style"><span class="std std-numref">Chapter 4</span></a>, this will ensure that the style rules
we intend to apply to each repository are selected correctly.</p>
<p>Open Visual Studio Code, and from the <code class="xref py py-obj docutils literal notranslate"><span class="pre">file</span></code> menu select <code class="xref py py-obj docutils literal notranslate"><span class="pre">open</span> <span class="pre">folder</span></code>. Choose
the top level workspace folder that you created in <a class="reference internal" href="1_introduction.html#working-folder"><span class="std std-numref">Section 1.2.1</span></a>
(you might have called this <code class="file docutils literal notranslate"><span class="pre">principles_of_programming</span></code>). You should now
be able to see this folder name in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">Explorer</span></code> panel on the left of the
Visual Studio Code screen, with the name of your venv folder beneath it.</p>
<p>Next, we need to save this workspace. From the <code class="xref py py-obj docutils literal notranslate"><span class="pre">file</span></code> menu select <code class="xref py py-obj docutils literal notranslate"><span class="pre">Save</span>
<span class="pre">Workspace</span> <span class="pre">As...</span></code> and click the <kbd class="kbd docutils literal notranslate">save</kbd> button (there’s no need to change
the filename). You’ll see a file called something like
<code class="file docutils literal notranslate"><span class="pre">principles_of_programming.code-workspace</span></code> appear in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">Explorer</span></code>
panel. This file contains workspace settings, and you can also click on it in
your operating system’s file explorer to start Visual Studio Code in this
workspace.</p>
<p>Finally, let’s create a test folder in which we’ll create our first Python
script. Open a terminal by clicking on the <code class="xref py py-obj docutils literal notranslate"><span class="pre">New</span> <span class="pre">Terminal</span></code> item in the
<code class="xref py py-obj docutils literal notranslate"><span class="pre">Terminal</span></code> menu of Visual Studio Code. Type the following:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>mkdir<span class="w"> </span><span class="nb">test</span>
</pre></div>
</div>
<p>You should see the <code class="file docutils literal notranslate"><span class="pre">test</span></code> folder appear in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">Explorer</span></code> panel. However,
we haven’t yet told Visual Studio Code to treat <a class="reference external" href="https://docs.python.org/3/library/test.html#module-test" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">test</span></code></a> as a top level code
folder. To do that, choose <code class="xref py py-obj docutils literal notranslate"><span class="pre">Add</span> <span class="pre">Folder</span> <span class="pre">to</span> <span class="pre">Workspace</span></code> from the <code class="xref py py-obj docutils literal notranslate"><span class="pre">file</span></code> menu, and
select the <a class="reference external" href="https://docs.python.org/3/library/test.html#module-test" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">test</span></code></a> folder. This will cause the folder to appear alongside the
workspace folder in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">Explorer</span></code> tab. <a class="reference internal" href="#vscode-workspace"><span class="std std-numref">Fig. 2.1</span></a> shows a
workspace in this configuration.</p>
<figure class="align-default" id="id8">
<span id="vscode-workspace"></span><a class="reference internal image-reference" href="_images/vscode_workspace.png"><img alt="_images/vscode_workspace.png" src="_images/vscode_workspace.png" style="width: 100%;" />
</a>
<figcaption>
<p><span class="caption-number">Fig. 2.1 </span><span class="caption-text">The Visual Studio Code debugging window showing a multi-root workspace
containing the top level <code class="file docutils literal notranslate"><span class="pre">principles_of_programming</span></code> folder, as
well as the <code class="file docutils literal notranslate"><span class="pre">test</span></code> folder. Note that the <code class="file docutils literal notranslate"><span class="pre">test</span></code> folder
is also visible inside the <code class="file docutils literal notranslate"><span class="pre">principles_of_programming</span></code> folder.</span><a class="headerlink" href="#id8" title="Link to this image">¶</a></p>
</figcaption>
</figure>
</section>
<section id="a-first-python-script">
<h3><span class="section-number">2.2.2. </span>A first Python script<a class="headerlink" href="#a-first-python-script" title="Link to this heading">¶</a></h3>
<p>Tradition dictates that the first stand-alone program one writes in any
language simply prints out the string <code class="xref py py-obj docutils literal notranslate"><span class="pre">Hello</span> <span class="pre">World</span></code>. Using an IDE or text
editor, we create a file in our <code class="file docutils literal notranslate"><span class="pre">test</span></code> folder, which we’ll call
<code class="file docutils literal notranslate"><span class="pre">hello.py</span></code> containing just the following line of Python code:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s2">"Hello World"</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="file docutils literal notranslate"><span class="pre">.py</span></code> file extension is not strictly required for Python scripts, but
it can be useful as it will cause most text editors to recognise the file as a
Python file. Having remembered to save <code class="file docutils literal notranslate"><span class="pre">hello.py</span></code> to disk from the text
editor, we can now run the program. Open a terminal, and activate your virtual
environment. Next, change to <code class="file docutils literal notranslate"><span class="pre">test</span></code>
folder. On most operating systems, you would type the following:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span><span class="nb">cd</span><span class="w"> </span><span class="nb">test</span>
<span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>hello.py
</pre></div>
</div>
<p>The first of these commands,
<code class="xref py py-obj docutils literal notranslate"><span class="pre">cd</span></code> (<em>change directory</em>) switches the current folder to <code class="file docutils literal notranslate"><span class="pre">test</span></code>. The
second command actually runs the Python interpreter on <code class="file docutils literal notranslate"><span class="pre">hello.py</span></code>. From
within our venv, we can be confident that <code class="xref py py-obj docutils literal notranslate"><span class="pre">python</span></code> will refer to the right
version of Python. When we press the
<kbd class="kbd docutils literal notranslate">enter</kbd> key after the last line above, our tiny Python script
<code class="file docutils literal notranslate"><span class="pre">hello.py</span></code> runs and the following is displayed:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="go">Hello World</span>
</pre></div>
</div>
</section>
<section id="when-to-use-scripts">
<h3><span class="section-number">2.2.3. </span>When to use scripts<a class="headerlink" href="#when-to-use-scripts" title="Link to this heading">¶</a></h3>
<p>The key advantage of a script is that it is repeatable: it can be
run again, and exactly the same commands will execute. Writing
scripts is an absolutely essential programming discipline in any
circumstance where you might want to know what you did and, possibly,
do it again. For example, suppose you have a project in a
computational statistics course, in which you need to apply a complex
sequence of operations to a dataset and then plot some resulting
quantities. You could simply do this in an interactive Python session,
but you are then totally dependent on your memory as to what
you did. If you make a mistake, then you <em>might</em> notice an error in the
final result, but you will almost certainly not recall the inadvertent
mistake that led to it.</p>
<p>Conversely, had you written every step you took as a Python script
which outputs the final plot to a pdf for inclusion in your report,
you can go back over your work and find the error. A particularly
frustrating phenomenon, often encountered shortly before a submission
deadline, is to suddenly discover that something which used to work no
longer does. If you took the next logical step and committed your
scripts to a Git repository, making a new commit every time you edit
it, you would also be able to go back and find the point at which the
script stopped working. We will return to this debugging technique in
<a class="reference internal" href="8_debugging.html#bisection-debugging"><span class="std std-numref">Section 8.7.2</span></a>.</p>
<div class="admonition hint">
<p class="admonition-title">Hint</p>
<p>Whenever you need to perform a calculation as a part of an assignment or
project, or as part of your job, <strong>always</strong> write a script to perform the
calculation and store that script under revision control. Adopting this
simple practice will save you enormous amounts of frustration and wasted
time over the course of your career.</p>
</div>
</section>
<section id="when-not-to-use-scripts">
<h3><span class="section-number">2.2.4. </span>When not to use scripts<a class="headerlink" href="#when-not-to-use-scripts" title="Link to this heading">¶</a></h3>
<p>The one thing that scripts can do is run. This makes them an
exceptional tool for reproducing calculations. However, as
mathematicians and programmers, we are also interested in building
tools which users can combine together in different ways. We also want
to make functions and other code objects which can be reused in
different contexts to perform more complex computations. Functions and
other data structures defined in a script can essentially only be used
in that script. As soon as a piece of code is intended to be used in
two different scripts, it should be taken out and placed in a
module. This means that scripts should usually be quite short lists of
calls out to code in modules. We’ll see a simple example of this
shortly.</p>
</section>
</section>
<section id="modules">
<span id="id1"></span><h2><span class="section-number">2.3. </span>Modules<a class="headerlink" href="#modules" title="Link to this heading">¶</a></h2>
<details>
<summary>
Video: a first Python module.</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/486845755" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=2f0cb956-9e78-4022-94ff-ae1c00da3b41">watch this video on Panopto</a></p>
</details><p>A module is, like a script, a plain text file containing Python
code. Modules must have names ending in <code class="file docutils literal notranslate"><span class="pre">.py</span></code>. So far, that’s
identical to a script. Indeed, it’s sometimes possible (though not
always advisable) to use the same file as both a script and a
module. The difference between a script and a module lies in how it is
used. A script is run, which means that a new Python interpreter
starts, executes the commands in the script, and then
exits. Conversely, a module is imported into a running Python
session. For example, suppose we create a file <code class="file docutils literal notranslate"><span class="pre">fibonacci.py</span></code>
containing the following simple function:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Return the n-th Fibonacci number."""</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="k">elif</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
<p>If we now run IPython in the folder containing our new file
<code class="file docutils literal notranslate"><span class="pre">fibonacci.py</span></code> then we will be able to import the <a class="reference internal" href="fibonacci.html#module-fibonacci" title="fibonacci"><code class="xref py py-mod docutils literal notranslate"><span class="pre">fibonacci</span></code></a>
module, and use the function <code class="xref py py-func docutils literal notranslate"><span class="pre">fib()</span></code>:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="kn">import</span><span class="w"> </span><span class="nn">fibonacci</span>
<span class="gp">In [2]: </span><span class="n">fibonacci</span><span class="o">.</span><span class="n">fib</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="gh">Out[2]: </span><span class="go">2</span>
</pre></div>
</div>
<p>Notice that we do not include the <code class="file docutils literal notranslate"><span class="pre">.py</span></code> suffix when we import a
module. Importing a module provides access to whatever it
contains. This is a key tool in building up algorithms out of
components: we import the components we need at each stage of our
programs.</p>
<section id="importing-and-namespaces">
<h3><span class="section-number">2.3.1. </span>Importing and namespaces<a class="headerlink" href="#importing-and-namespaces" title="Link to this heading">¶</a></h3>
<p>When we imported the module <a class="reference internal" href="fibonacci.html#module-fibonacci" title="fibonacci"><code class="xref py py-mod docutils literal notranslate"><span class="pre">fibonacci</span></code></a>, this created the name
<a class="reference internal" href="fibonacci.html#module-fibonacci" title="fibonacci"><code class="xref py py-obj docutils literal notranslate"><span class="pre">fibonacci</span></code></a> in the current environment. The code in <code class="xref py py-obj docutils literal notranslate"><span class="pre">fibonacci.py</span></code> is
then run, and any names defined in that code (such as the function
<code class="xref py py-func docutils literal notranslate"><span class="pre">fib()</span></code>) are defined within the <a class="reference internal" href="#term-namespace"><span class="xref std std-term">namespace</span></a> <a class="reference internal" href="fibonacci.html#module-fibonacci" title="fibonacci"><code class="xref py py-obj docutils literal notranslate"><span class="pre">fibonacci</span></code></a>. As
we begin to compose together code from different parts of mathematics,
the ability to separate identically named but different objects from
each other is essential. For example, Python has a module containing
core real-valued maths functions called <a class="reference external" href="https://docs.python.org/3/library/math.html#module-math" title="(in Python v3.14)"><code class="docutils literal notranslate"><span class="pre">math</span></code></a>, and one
containing complex maths functions called
<a class="reference external" href="https://docs.python.org/3/library/cmath.html#module-cmath" title="(in Python v3.14)"><code class="docutils literal notranslate"><span class="pre">cmath</span></code></a>. Clearly, it’s important that we can distinguish
between <a class="reference external" href="https://docs.python.org/3/library/math.html#math.sin" title="(in Python v3.14)"><code class="docutils literal notranslate"><span class="pre">math.sin()</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/cmath.html#cmath.sin" title="(in Python v3.14)"><code class="docutils literal notranslate"><span class="pre">cmath.sin()</span></code></a>. Here the
module names <a class="reference external" href="https://docs.python.org/3/library/math.html#module-math" title="(in Python v3.14)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">math</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/cmath.html#module-cmath" title="(in Python v3.14)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">cmath</span></code></a> form the namespaces that
differentiate between the two <code class="xref py py-func docutils literal notranslate"><span class="pre">sin()</span></code> functions.</p>
<p>There are essentially only two core namespace concepts. One of them is that
every name is in a namespace, and any given time points to a unique value. The
second one is that namespaces can be nested, so a name in a namespace can
itself be another namespace. For example, the math namespace contains the value
<a class="reference external" href="https://docs.python.org/3/library/math.html#math.pi" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">math.pi</span></code></a>, which itself defines a namespace for some operations that are
built into Python numbers. The (somewhat uninteresting) imaginary part of π can
be accessed as <code class="xref py py-obj docutils literal notranslate"><span class="pre">math.pi.imag</span></code>.</p>
<p>Namespaces are a simple but fundamental concept in programming. To
quote one of the key developers of the Python language:</p>
<blockquote>
<div><p>Namespaces are one honking great idea – let’s do more of those! <a class="footnote-reference brackets" href="#peters" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a></p>
</div></blockquote>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><a class="reference internal" href="#term-namespace"><span class="xref std std-term">Namespaces</span></a> may look unfamiliar at first, but
actually, they are such a natural concept that you have been working
with them for as long as you have used a computer, without even
thinking about it. This is because folders are simply namespaces
for files. Each filename can exist only once in each folder, and
folders can be nested inside folders.</p>
</div>
</section>
<section id="other-forms-of-import">
<h3><span class="section-number">2.3.2. </span>Other forms of import<a class="headerlink" href="#other-forms-of-import" title="Link to this heading">¶</a></h3>
<p>Importing modules into their own namespaces is frequently what we
want: it clearly separates the names in the module from the names we
have defined ourselves, and makes it very obvious to a reader where
the names come from. The downside is that names in namespaces can be
quite long and cumbersome, which is particularly inconvenient if names
are to be used frequently or in the middle of expressions: you probably
don’t really want to write <a class="reference external" href="https://docs.python.org/3/library/math.html#math.sin" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">math.sin()</span></code></a> in every trig formula you
ever write. One alternative is to rename the module on import. This is
achieved using the keyword <a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#import" title="(in Python v3.14)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">as</span></code></a> in an import statement. For example,
it is usual to import the numerical Python module <a class="reference external" href="https://numpy.org/doc/stable/reference/index.html#module-numpy" title="(in NumPy v2.3)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">numpy</span></code></a> in the
following way:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">numpy</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">np</span>
</pre></div>
</div>
<p>This creates the local name <a class="reference external" href="https://numpy.org/doc/stable/reference/index.html#module-numpy" title="(in NumPy v2.3)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">np</span></code></a> instead of <a class="reference external" href="https://numpy.org/doc/stable/reference/index.html#module-numpy" title="(in NumPy v2.3)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">numpy</span></code></a>,
so that the function for creating an evenly spaced sequence of values
between to end points is now accessible as <a class="reference external" href="https://numpy.org/doc/stable/reference/generated/numpy.linspace.html#numpy.linspace" title="(in NumPy v2.3)"><code class="xref py py-func docutils literal notranslate"><span class="pre">np.linspace</span></code></a>.</p>
<p>A second option is to import particular names from a module directly
into the current namespace. For example, if we planned to use the
functions <a class="reference external" href="https://docs.python.org/3/library/math.html#math.sin" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">math.sin()</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/math.html#math.cos" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">math.cos()</span></code></a> a lot in our script, we
might use the following import statement:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">math</span><span class="w"> </span><span class="kn">import</span> <span class="n">sin</span><span class="p">,</span> <span class="n">cos</span>
</pre></div>
</div>
<p>Now we can use the names <a class="reference external" href="https://docs.python.org/3/library/math.html#math.sin" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">sin</span></code></a> and <a class="reference external" href="https://docs.python.org/3/library/math.html#math.cos" title="(in Python v3.14)"><code class="xref py py-func docutils literal notranslate"><span class="pre">cos</span></code></a> directly. What if we also wanted to use a short name for
their complex counterparts? We can’t have two functions with the same
name in a single <a class="reference internal" href="#term-namespace"><span class="xref std std-term">namespace</span></a>. Fortunately, the keyword <code class="xref py py-obj docutils literal notranslate"><span class="pre">as</span></code>
comes to our rescue again:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">cmath</span><span class="w"> </span><span class="kn">import</span> <span class="n">sin</span> <span class="k">as</span> <span class="n">csin</span><span class="p">,</span> <span class="n">cos</span> <span class="k">as</span> <span class="n">ccos</span>
</pre></div>
</div>
<p>Renaming on import is a double-edged sword. You must always take care
that renaming does not add to the confusion. As a somewhat extreme
example, should you ever type the following code, you should expect
the wrath of your users to be without bounds:</p>
<div class="badcode docutils container">
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">math</span><span class="w"> </span><span class="kn">import</span> <span class="n">sin</span> <span class="k">as</span> <span class="n">cos</span><span class="p">,</span> <span class="n">cos</span> <span class="k">as</span> <span class="n">sin</span>
</pre></div>
</div>
</div>
<p>It is possible to import all of the names from a module into the current namespace:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">math</span><span class="w"> </span><span class="kn">import</span> <span class="o">*</span>
</pre></div>
</div>
<p>Now everything in the math module can be used without a namespace
prefix. This may seem superficially attractive, but actually importing
<code class="xref py py-obj docutils literal notranslate"><span class="pre">*</span></code> is a frequent source of problems. For starters, if you import <code class="xref py py-obj docutils literal notranslate"><span class="pre">*</span></code>
from more than one module, it becomes impossible for the reader of the
code to work out from which module each name comes. Further, if a
module from which you import <code class="xref py py-obj docutils literal notranslate"><span class="pre">*</span></code> contains a name that you have already
used, then the meaning of that name will be overwritten with the one
from the module (without any warning or error). This is a frequent
source of confusion. For this reason, importing <code class="xref py py-obj docutils literal notranslate"><span class="pre">*</span></code> is usually a bad
idea.</p>
<p>The full details of all the ways that the import statement can be used
is in <a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#import" title="(in Python v3.14)"><span class="xref std std-ref">the official Python Language Reference.</span></a></p>
</section>
</section>
<section id="packages">
<h2><span class="section-number">2.4. </span>Packages<a class="headerlink" href="#packages" title="Link to this heading">¶</a></h2>
<details>
<summary>
Video: a first Python package.</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/487003753" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=4f600702-02e0-4f9a-8edb-af8601177507">watch this video on Panopto</a></p>
</details><p>Modules are the principal mechanism for storing code which is intended
to be used by other code. However, putting all of the code for a
complex area of mathematics in a single huge Python file is not a
great idea. Readers of that code will struggle to see the logical
structure of thousands or tens of thousands of lines of code. It would
be much more logical, and much easier to work with, to split the code
up into several files of more reasonable length. This is where
packages come in. A Python package is a collection of module files,
which can be imported together. The basic folder structure of a Python
package is shown in <a class="reference internal" href="#package-layout"><span class="std std-numref">Listing 2.1</span></a>.</p>
<div class="literal-block-wrapper docutils container" id="id9">
<span id="package-layout"></span><div class="code-block-caption"><span class="caption-number">Listing 2.1 </span><span class="caption-text">The file layout for a simple package.</span><a class="headerlink" href="#id9" title="Link to this code">¶</a></div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>my_git_repo
├── my_package
│ ├── __init__.py
│ ├── module_1.py
│ ├── module_2.py
│ └── subpackage
│ ├── __init__.py
│ └── module_3.py
└── pyproject.toml
</pre></div>
</div>
</div>
<p>If you haven’t seen a diagram like this before, the names with lines
descending from their first letter are folder names, and the
descending line connects the folder name to the files and folders it
contains. Let’s walk through these files and folders to understand how
they make up the Python package.</p>
<dl>
<dt><code class="file docutils literal notranslate"><span class="pre">my_git_repo</span></code></dt><dd><p>This is not really a part of the package at all, but the
<code class="file docutils literal notranslate"><span class="pre">my_package</span></code> folder needs to be in some folder, and this is a
reminder that all your work should be in a revision control system
such as <a class="reference internal" href="a2_git.html#git"><span class="std std-ref">Git</span></a>. It is usual for
package folders to be contained immediately in the top level of
the repository, in the manner shown here.</p>
</dd>
<dt><code class="file docutils literal notranslate"><span class="pre">my_package</span></code></dt><dd><p>This is the actual package. The name of this folder sets the
package name, so if you really made a package folder with this
name, then you would type:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">my_package</span>
</pre></div>
</div>
<p>to access the package.</p>
</dd>
<dt><code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code></dt><dd><p>Every package must contain a file with <em>exactly</em> this name. This is
how Python recognises that a folder is a package. <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code>
can be an empty file, or it can contain code to populate the top
level <a class="reference internal" href="#term-namespace"><span class="xref std std-term">namespace</span></a> of the package. See <a class="reference internal" href="#importing-packages"><span class="std std-numref">Section 2.4.1</span></a> below.</p>
</dd>
<dt><code class="file docutils literal notranslate"><span class="pre">module_1.py</span></code>, <code class="file docutils literal notranslate"><span class="pre">module_2.py</span></code></dt><dd><p>These are just Python <a class="reference internal" href="#term-module"><span class="xref std std-term">modules</span></a>. If the user imports
<code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package</span></code> using the line above then these modules will appear
as <code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package.module_1</span></code> and <code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package.module_2</span></code> respectively.</p>
</dd>
<dt><code class="file docutils literal notranslate"><span class="pre">subpackage</span></code></dt><dd><p>Packages can contain packages. A subpackage is just a folder
containing a file <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code>. It can also contain modules and
further subpackages.</p>
</dd>
<dt><code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code></dt><dd><p>This file is outside the package folder and is not
actually a part of the package. The role of <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> will be
covered in <a class="reference internal" href="#installable-packages"><span class="std std-numref">Section 2.4.2</span></a>.</p>
</dd>
</dl>
<section id="importing-packages">
<span id="id4"></span><h3><span class="section-number">2.4.1. </span>Importing packages<a class="headerlink" href="#importing-packages" title="Link to this heading">¶</a></h3>
<p>The system for importing packages is the same as that described for modules in
<a class="reference internal" href="#modules"><span class="std std-numref">Section 2.3</span></a>, though the nested nature of packages makes the process
somewhat more involved. Importing a package also imports all the modules it
contains, including those in subpackages. This will establish a set of nested
namespaces. In the example above, let’s suppose we have imported
<code class="xref py py-mod docutils literal notranslate"><span class="pre">my_package</span></code>. <code class="xref py py-mod docutils literal notranslate"><span class="pre">module_3</span></code> will be accessible as
<code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package.subpackage.module_3</span></code>. The usual rules about the <code class="xref py py-obj docutils literal notranslate"><span class="pre">from</span></code> keyword
still apply, so:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">my_package.subpackages</span><span class="w"> </span><span class="kn">import</span> <span class="n">module_3</span>
</pre></div>
</div>
<p>would import the name <code class="xref py py-obj docutils literal notranslate"><span class="pre">module_3</span></code> straight into the current local
namespace.</p>
<p>The file <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code> is itself a module and will be imported when
the package is imported. However, names defined in <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code> will
appear directly in the namespace of the package. This is usually used
to extract names from submodules that are supposed to be directly
accessed by users of the package.</p>
<p>For example, suppose that <code class="xref py py-obj docutils literal notranslate"><span class="pre">module_1</span></code> contains a function
<code class="xref py py-obj docutils literal notranslate"><span class="pre">my_func</span></code>. Then the top level <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code> in <code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package</span></code> might contain
the line:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">.module_1</span><span class="w"> </span><span class="kn">import</span> <span class="n">my_func</span>
</pre></div>
</div>
<p>The result of this would be that the user of <code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package</span></code> would be
able to access <code class="xref py py-obj docutils literal notranslate"><span class="pre">my_func</span></code> as <code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package.my_func</span></code> (though
<code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package.module_1.my_func</span></code> would also work). This sort of
arrangement provides a mechanism for the programmer to arrange the
internal module structure of a package in a logical way while still
providing users with direct access to the most important or most
frequently used features.</p>
<p>The eagle-eyed reader will have noticed the extra . in front of
<code class="xref py py-obj docutils literal notranslate"><span class="pre">module_1</span></code>. This marks this import as a <em>relative import</em>. In other
words, in looking for <code class="file docutils literal notranslate"><span class="pre">module_1.py</span></code>, Python should look for files in
the same folder as the module where the import statement occurs,
instead of looking for an external package called <code class="xref py py-obj docutils literal notranslate"><span class="pre">module_1</span></code>. We could
have equivalently written:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">my_package.module_1</span><span class="w"> </span><span class="kn">import</span> <span class="n">my_func</span>
</pre></div>
</div>
<p>but the relative import is shorter and provides a reminder to the
reader that the import is from the current package.</p>
</section>
<section id="making-packages-installable">
<span id="installable-packages"></span><h3><span class="section-number">2.4.2. </span>Making packages installable<a class="headerlink" href="#making-packages-installable" title="Link to this heading">¶</a></h3>
<p>In order for the <a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#import" title="(in Python v3.14)"><span class="xref std std-ref">import statement</span></a> to work, Python needs
to know that the package being imported exists, and where to find it. This is
achieved by installing the package using Pip. In order to make a package
installable, we need to provide Pip with a bit more information about it. The
modern way to provide this information is using a configuration file which must
be called <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code>. This file isn’t part of the package and does
not go in the package folder. Instead, it should be placed in the top-level
folder of your git repository, so that the Python package installer will be
able to find it.</p>
<div class="literal-block-wrapper docutils container" id="id10">
<span id="minimal-pyproject-toml"></span><div class="code-block-caption"><span class="caption-number">Listing 2.2 </span><span class="caption-text">A minimal <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> which will make the <code class="xref py py-obj docutils literal notranslate"><span class="pre">my_package</span></code>
package installable.</span><a class="headerlink" href="#id10" title="Link to this code">¶</a></div>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">build</span><span class="o">-</span><span class="n">system</span><span class="p">]</span>
<span class="n">requires</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"hatchling"</span><span class="p">]</span>
<span class="n">build</span><span class="o">-</span><span class="n">backend</span> <span class="o">=</span> <span class="s2">"hatchling.build"</span>
<span class="p">[</span><span class="n">project</span><span class="p">]</span>
<span class="n">name</span> <span class="o">=</span> <span class="s2">"my_package"</span>
<span class="n">version</span> <span class="o">=</span> <span class="s2">"0.1"</span>
<span class="p">[</span><span class="n">tool</span><span class="o">.</span><span class="n">hatch</span><span class="o">.</span><span class="n">build</span><span class="o">.</span><span class="n">targets</span><span class="o">.</span><span class="n">wheel</span><span class="p">]</span>
<span class="n">packages</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"my_package"</span><span class="p">]</span>
</pre></div>
</div>
</div>
<p><a class="reference internal" href="#minimal-pyproject-toml"><span class="std std-numref">Listing 2.2</span></a> shows a very basic <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code>.
This isn’t a Python file, instead it’s a configuration file written in a
language called <a class="reference external" href="https://toml.io/en/">TOML</a>. In our case, the TOML file
comprises three sections, which TOML calls “tables”.</p>
<p>The first table is called <code class="xref py py-obj docutils literal notranslate"><span class="pre">build-system</span></code>, and enables us to choose which of the
various Python project management packages we wish to use. For our very simple
package we’ll use <code class="xref py py-obj docutils literal notranslate"><span class="pre">hatchling</span></code> which is part of the Python project management
system <code class="xref py py-obj docutils literal notranslate"><span class="pre">Hatch</span></code>. There are a number of other packages
we could have used for this, but for our simple purposes it doesn’t much matter
which we use. Inside tables, TOML records configuration information as
key-value pairs. There are two keys that we must set in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">build-system</span></code>
table. <code class="xref py py-obj docutils literal notranslate"><span class="pre">requires</span></code> is a list of packages that Pip should install in order to
build this package. In this case, that is just <code class="xref py py-obj docutils literal notranslate"><span class="pre">hatchling</span></code>. The second key we
need is <code class="xref py py-obj docutils literal notranslate"><span class="pre">build-backend</span></code>. This is the name of the Python module that will be
used to build the package. For <code class="xref py py-obj docutils literal notranslate"><span class="pre">hatchling</span></code> this is the <code class="xref py py-obj docutils literal notranslate"><span class="pre">build</span></code> module in so we
write <code class="xref py py-obj docutils literal notranslate"><span class="pre">hatchling.build</span></code>.</p>
<p>The <code class="xref py py-obj docutils literal notranslate"><span class="pre">project</span></code> table contains information about the Pip package we’re creating.
At a minimum, we need to give our Pip package a name and a version number.
Finally, the <code class="xref py py-obj docutils literal notranslate"><span class="pre">packages</span></code> key in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">[tool.hatch.build.targets.wheel]</span></code> table
contains the list of Python package folders to be included.</p>
<p>This very simple <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> will suffice for packages that you
only intend to use yourself. Should you wish to publish packages for use by
other people, then you’ll need to provide significantly more information in
<code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> and, potentially, in other places too. The canonical
guide to this is the <a class="reference external" href="https://packaging.python.org/tutorials/packaging-projects/">Python Packaging User Guide</a>.</p>
</section>
<section id="installing-a-package-from-local-code">
<h3><span class="section-number">2.4.3. </span>Installing a package from local code<a class="headerlink" href="#installing-a-package-from-local-code" title="Link to this heading">¶</a></h3>
<p>In <a class="reference internal" href="1_introduction.html#install-from-pypi"><span class="std std-numref">Section 1.3.1</span></a> we learned how to use Pip to install packages
from the online Python package repository, PyPI. However, Pip can also be used
to install a package from a folder on your computer. In this case,
you would type:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>-e<span class="w"> </span>folder/
</pre></div>
</div>
<p>replacing <code class="file docutils literal notranslate"><span class="pre">folder</span></code> with the name of the top-level folder of your
repository: the folder containing <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code>. The option flag <code class="xref py py-obj docutils literal notranslate"><span class="pre">-e</span></code> tells
Pip to install the package in ‘editable’ mode. This means that instead of
copying the package files to your venv’s Python packages folder, symbolic links
will be created. Consequently, any changes that you make to your package will
show up the next time the package is imported in a new Python process, avoiding
the need to reinstall the package every time you change it.</p>
<p>The name <code class="xref py py-obj docutils literal notranslate"><span class="pre">folder</span></code> in the example above is an example of a relative path. This
means that <code class="xref py py-obj docutils literal notranslate"><span class="pre">folder</span></code> is located relative to the folder in which the command
<code class="xref py py-obj docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">pip</span></code> is run. It often happens that a user wants to install the
package whose <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> is in the current folder. In this case
it’s helpful to know that the special relative path <code class="file docutils literal notranslate"><span class="pre">.</span></code> refers to the
current folder. So to install the package defined in the current folder, type:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>-e<span class="w"> </span>.
</pre></div>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>If you edit a package, even one installed in editable mode, an
already running Python process which has already imported that
package will not notice the change. This is a common cause of
confusion for users who are editing packages and testing them using
an interactive Python tool such as IPython or a Jupyter Notebook. A
major advantage of a Python script is that a new Python process is
started every time the script is run, so the packages used are
guaranteed to be up to date.</p>
</div>
</section>
<section id="pip-packages-and-python-packages">
<h3><span class="section-number">2.4.4. </span>Pip packages and Python packages<a class="headerlink" href="#pip-packages-and-python-packages" title="Link to this heading">¶</a></h3>
<p>One frequent source of confusion in making packages installable and actually
installing them is that Pip and Python have slightly different definitions of
what constitutes a package. A Python package, as we have just learned, is a
folder containing (at least) a file called <code class="file docutils literal notranslate"><span class="pre">__init__.py</span></code>. For Pip,
however, a package is everything that <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> installs, which
could include any number of Python packages.</p>
</section>
<section id="package-dependencies">
<h3><span class="section-number">2.4.5. </span>Package dependencies<a class="headerlink" href="#package-dependencies" title="Link to this heading">¶</a></h3>
<p>There is one more feature of Pip packages that it is useful to introduce at
this stage: dependencies. If you write a package and the modules in that
package themselves import other packages, then a user will need those packages
to be installed in their Python environment, or your package will not work. If
your package depends on other packages that need to be installed from PyPI then
steps need to be taken to ensure that your users will have the correct packages
installed. The <code class="xref py py-obj docutils literal notranslate"><span class="pre">dependencies</span></code> key in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">project</span></code> table provides a list of
packages on which the current package depends. Pip will install any of these
packages that are not already available before installing the package itself.
<a class="reference internal" href="#dependency-pyproject-toml"><span class="std std-numref">Listing 2.3</span></a> illustrates this by adding a dependency on
<a class="reference external" href="https://numpy.org/doc/stable/reference/index.html#module-numpy" title="(in NumPy v2.3)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">numpy</span></code></a>.</p>
<div class="literal-block-wrapper docutils container" id="id11">
<span id="dependency-pyproject-toml"></span><div class="code-block-caption"><span class="caption-number">Listing 2.3 </span><span class="caption-text">An extension to the <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code> from
<a class="reference internal" href="#minimal-pyproject-toml"><span class="std std-numref">Listing 2.2</span></a> to require that <a class="reference external" href="https://numpy.org/doc/stable/reference/index.html#module-numpy" title="(in NumPy v2.3)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">numpy</span></code></a> is installed.</span><a class="headerlink" href="#id11" title="Link to this code">¶</a></div>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">build</span><span class="o">-</span><span class="n">system</span><span class="p">]</span>
<span class="n">requires</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"hatchling"</span><span class="p">]</span>
<span class="n">build</span><span class="o">-</span><span class="n">backend</span> <span class="o">=</span> <span class="s2">"hatchling.build"</span>
<span class="p">[</span><span class="n">project</span><span class="p">]</span>
<span class="n">name</span> <span class="o">=</span> <span class="s2">"my_package"</span>
<span class="n">version</span> <span class="o">=</span> <span class="s2">"0.1"</span>
<span class="n">dependencies</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"numpy"</span><span class="p">]</span>
<span class="p">[</span><span class="n">tool</span><span class="o">.</span><span class="n">hatch</span><span class="o">.</span><span class="n">build</span><span class="o">.</span><span class="n">targets</span><span class="o">.</span><span class="n">wheel</span><span class="p">]</span>
<span class="n">packages</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"my_package"</span><span class="p">]</span>
</pre></div>
</div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>It is important to understand the difference between the <code class="xref py py-obj docutils literal notranslate"><span class="pre">requires</span></code> key in
the <code class="xref py py-obj docutils literal notranslate"><span class="pre">build-system</span></code> table and the <code class="xref py py-obj docutils literal notranslate"><span class="pre">dependencies</span></code> key in the <code class="xref py py-obj docutils literal notranslate"><span class="pre">project</span></code> table.
The former is a list of packages needed to build the package, while the
latter is a list of packages needed to use the current package. You will
often need to specify <code class="xref py py-obj docutils literal notranslate"><span class="pre">dependencies</span></code> but, unless you are doing something
quite advanced such as writing Python packages in another programming
language, you will not need to add to <code class="xref py py-obj docutils literal notranslate"><span class="pre">requires</span></code>.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Neither <code class="xref py py-obj docutils literal notranslate"><span class="pre">dependencies</span></code> nor <code class="xref py py-obj docutils literal notranslate"><span class="pre">requires</span></code> should list packages from the Python
Standard Library. These are always available, and listing them will cause
Pip to error.</p>
</div>
</section>
</section>
<section id="testing-frameworks">
<h2><span class="section-number">2.5. </span>Testing frameworks<a class="headerlink" href="#testing-frameworks" title="Link to this heading">¶</a></h2>
<details>
<summary>
Video: introducing Pytest.</summary><div class="video_wrapper" style="">
<iframe allowfullscreen="true" src="https://player.vimeo.com/video/486987209" style="border: 0; height: 345px; width: 560px">
</iframe></div><p>Imperial students can also <a class="reference external" href="https://imperial.cloud.panopto.eu/Panopto/Pages/Viewer.aspx?id=73421f63-998c-4273-9c41-ae1c00da4624">watch this video on Panopto</a></p>
</details><p>Attempting to establish whether a program correctly implements the intended
algorithm is core to effective programming, and programmers often spend more
time correcting bugs than writing new code. We will turn to the question of how
to debug in <a class="reference internal" href="8_debugging.html#debugging"><span class="std std-numref">Chapter 8</span></a>. However, right from the start, we
need to test the code we write, so we will cover the practical details of
including tests in your code here.</p>
<p>There are a number of Python packages which support code testing. The concepts
are largely similar so rather than get bogged down in the details of multiple
frameworks, we will introduce <a class="reference external" href="https://docs.pytest.org/en/latest/index.html" title="(in pytest v9.1.0.dev134)"><span class="xref std std-doc">Pytest</span></a>, which is one of the
most widely used. Pytest is simply a Python package, so you can install it into
your current environment using:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>pytest
</pre></div>
</div>
<section id="pytest-tests">
<h3><span class="section-number">2.5.1. </span>Pytest tests<a class="headerlink" href="#pytest-tests" title="Link to this heading">¶</a></h3>
<p>A Pytest test is simply a function whose name starts with <code class="xref py py-obj docutils literal notranslate"><span class="pre">test_</span></code>. In the
simplest case, the function has no arguments. Pytest will call each such
function in turn. If the function executes without error, then the test is
taken to have passed, while if an error occurs then the test has failed. This
behaviour might at first seem surprising - we don’t just want the code to run,
it has to get the right answer. However, if we think about it the other way
around, we certainly want the test to fail if an error occurs. It’s also very
easy to arrange things such that an error occurs when the wrong answer is
reached. This is most readily achieved using <a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#assert" title="(in Python v3.14)"><span class="xref std std-ref">the assert statement</span></a>. This simply consists of <code class="xref py py-obj docutils literal notranslate"><span class="pre">assert</span></code> followed by a Python
expression. If the expression is true, then execution just continues, but if
it’s false, then an error occurs. For example:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="o">--------------------------------------------------------------------------</span>
<span class="ne">AssertionError</span> <span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">)</span>
<span class="n">Cell</span> <span class="n">In</span> <span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">line</span> <span class="mi">1</span>
<span class="o">----></span> <span class="mi">1</span> <span class="k">assert</span> <span class="mi">1</span><span class="o">==</span><span class="mi">0</span>
<span class="ne">AssertionError</span><span class="p">:</span>
</pre></div>
</div>
</section>
<section id="pytest-files">
<h3><span class="section-number">2.5.2. </span>Pytest files<a class="headerlink" href="#pytest-files" title="Link to this heading">¶</a></h3>
<p>Pytest looks for tests in files whose name starts with <code class="file docutils literal notranslate"><span class="pre">test_</span></code> and
ends with <code class="file docutils literal notranslate"><span class="pre">.py</span></code>. Continuing with our Fibonacci example, we might
create a file called <code class="file docutils literal notranslate"><span class="pre">test_fibonacci.py</span></code> containing:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">fibonacci</span><span class="w"> </span><span class="kn">import</span> <span class="n">fib</span>
<span class="k">def</span><span class="w"> </span><span class="nf">test_fibonacci_values</span><span class="p">():</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">f</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">8</span><span class="p">]):</span>
<span class="k">assert</span> <span class="n">fib</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="n">f</span>
</pre></div>
</div>
<p>These files don’t themselves form part of the package, instead they
are usually gathered in a separate tests folder. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>fibonacci
├── fibonacci
│ ├── __init__.py
│ └── fibonacci.py
├── tests
│ └── test_fibonacci.py
└── pyproject.toml
</pre></div>
</div>
<p>We can then invoke the tests from the shell:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span><span class="nb">cd</span><span class="w"> </span>fibonacci
<span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pytest<span class="w"> </span>tests
<span class="go">========================== test session starts ===========================</span>
<span class="go">platform darwin -- Python 3.7.7, pytest-5.4.1, py-1.8.1, pluggy-0.13.1</span>
<span class="go">rootdir: /Users/dham/docs/object-oriented-programming, inifile: setup.cfg</span>
<span class="go">collected 1 item</span>
<span class="go"> . [100%]</span>
<span class="go">=========================== 1 passed in 0.01s ============================</span>
</pre></div>
</div>
<p>The single dot indicates that we passed the one test in
<code class="xref py py-obj docutils literal notranslate"><span class="pre">test_fibonacci.py</span></code>. Had we made an error in our code, we would
instead see something like:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pytest<span class="w"> </span>tests
<span class="go">========================== test session starts ===========================</span>
<span class="go">platform darwin -- Python 3.7.7, pytest-5.4.1, py-1.8.1, pluggy-0.13.1</span>
<span class="go">rootdir: /Users/dham/docs/object-oriented-programming, inifile: setup.cfg</span>
<span class="go">collected 1 item</span>
<span class="go">tests/test_fibonacci.py F [100%]</span>
<span class="go">================================ FAILURES ================================</span>
<span class="go">_________________________ test_fibonacci_values __________________________</span>
<span class="go"> def test_fibonacci_values():</span>
<span class="go"> for i, f in enumerate([1, 1, 2, 3, 5, 8]):</span>
<span class="go">> assert fib(i+1) == f</span>
<span class="go">E assert 2 == 1</span>
<span class="go">E + where 2 = fib((1 + 1))</span>
<span class="go">tests/test_fibonacci.py:6: AssertionError</span>
<span class="go">======================== short test summary info =========================</span>
<span class="go">FAILED tests/test_fibonacci.py::test_fibonacci_values - assert 2 == 1</span>
<span class="go">=========================== 1 failed in 0.12s ============================</span>
</pre></div>
</div>
<p>Here we can see an <code class="xref py py-obj docutils literal notranslate"><span class="pre">F</span></code> after <code class="xref py py-obj docutils literal notranslate"><span class="pre">tests/test_fibonacci.py</span></code> indicating
that the test failed, and we see some output detailing what went
wrong. We will learn how to interpret this output in <a class="reference internal" href="6_exceptions.html#errors-and-exceptions"><span class="std std-numref">Chapter 6</span></a>.</p>
</section>
<section id="additional-useful-pytest-tricks">
<h3><span class="section-number">2.5.3. </span>Additional useful Pytest tricks<a class="headerlink" href="#additional-useful-pytest-tricks" title="Link to this heading">¶</a></h3>
<p>It can be useful to run a specific test file, which is achieved simply by naming
that file as the argument to Pytest. For example:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pytest<span class="w"> </span>tests/test_fibonacci.py
</pre></div>
</div>
<p>It is even possible to select an individual test to run, using a double colon
<code class="xref py py-obj docutils literal notranslate"><span class="pre">::</span></code> followed by the test name:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pytest<span class="w"> </span>tests/test_fibonacci.py::test_fibonacci_values
</pre></div>
</div>
<p>Often if one test fails then the same problem in your code will cause a whole
series of tests to fail, resulting in a very long list of error messages which
is hard to read. A useful tool in this circumstance is the <code class="xref py py-obj docutils literal notranslate"><span class="pre">-x</span></code> option, which
tells Pytest to stop after the first test fail. For example:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pytest<span class="w"> </span>-x<span class="w"> </span>tests
</pre></div>
</div>
<p>The tests are often arranged in increasing order of sophistication, so the
earlier tests are likely to catch the most basic errors in your code. For this
reason, it is usually the best policy to try to fix the first error first, and
only move onto the next problem when the previous test passes.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The exercise repositories that accompany this book will contain a
<code class="file docutils literal notranslate"><span class="pre">tests</span></code> folder full of tests that check that you have correctly
implemented the chapter’s exercises. You should get in the habit of running
the tests as you work through the exercises, as they are designed not just
to pass if your code is correct, but to provide feedback as to what might
be going wrong if your code contains errors.</p>
</div>
</section>
</section>
<section id="writing-code-to-a-specified-interface">
<h2><span class="section-number">2.6. </span>Writing code to a specified interface<a class="headerlink" href="#writing-code-to-a-specified-interface" title="Link to this heading">¶</a></h2>
<p>Creating more capable programs depends completely on being able to interface
different pieces of code. You will write code which calls code written by other
people, and others will call code written by you. This can only work if the
caller and the callee agree exactly on the interface: what are the names of the
<a class="reference internal" href="#term-package"><span class="xref std std-term">packages</span></a>, <a class="reference internal" href="#term-module"><span class="xref std std-term">modules</span></a> and functions being
called. How many arguments do they take? What are the names of the
<a class="reference external" href="https://docs.python.org/3/glossary.html#term-parameter" title="(in Python v3.14)"><span class="xref std std-term">keyword parameters</span></a>? Computer languages are notoriously
pedantic about such things: they have no capability to simply read through
small differences as a human would. You have doubtless already encountered the
frustrating situation of spending extended periods repeatedly getting errors
until you realised that something has to be spelt slightly differently, or that
you used a capital letter where you should have used a lower case one.</p>
<p>What changes as you move on to write code which will be called by other code is
that this need for precision and pedantry now flows in both directions. Not
only do you need to call other code using precisely the correct interface, you
also need to provide precisely the correct interface to the code that will call
you. This is particularly true when working with a testing framework, as the
tests for each exercise will call your code. The exercises will specify what
the correct interface is, either in the exercise question itself, or through
the skeleton code which is provided.</p>
<p>Your code needs to follow exactly the specification in the exercise: all the
right names, accepting arguments of the correct type and so on. If it does not,
then the tests will simply fail. Changing the tests to suit your preferred
interface is not an acceptable answer, your code needs to comply with the
interface specified in the tests.</p>
<p>This requirement to code to a published specification is not an artifact of the
testing framework: it is often the case that code written in a research or
business setting needs to conform with a standard or other published interface
exactly to create the sort of interoperability we’ve been discussing. Learning
to code to specification is therefore an important programming skill.</p>
</section>
<section id="glossary">
<h2><span class="section-number">2.7. </span>Glossary<a class="headerlink" href="#glossary" title="Link to this heading">¶</a></h2>
<blockquote>
<div><dl class="simple glossary">
<dt id="term-module">module<a class="headerlink" href="#term-module" title="Link to this term">¶</a></dt><dd><p>A text file containing Python code which is accessed using the
<a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#import" title="(in Python v3.14)"><span class="xref std std-ref">import statement</span></a>.</p>
</dd>
<dt id="term-namespace">namespace<a class="headerlink" href="#term-namespace" title="Link to this term">¶</a></dt><dd><p>A collection of names. Within a single namespace, each name has a single
defined meaning. Names in different spaces can be referred to using the
syntax <code class="xref py py-obj docutils literal notranslate"><span class="pre">namespace.name</span></code> where <code class="xref py py-obj docutils literal notranslate"><span class="pre">namespace</span></code> is an name for the namespace.
namespaces are themselves named, so they can be nested
(<code class="xref py py-obj docutils literal notranslate"><span class="pre">namespace.inner_namespace.name</span></code>).</p>
</dd>
<dt id="term-package">package<a class="headerlink" href="#term-package" title="Link to this term">¶</a></dt><dd><p>A grouping of related <a class="reference internal" href="#term-module"><span class="xref std std-term">modules</span></a> into a single importable
unit.</p>
</dd>
<dt id="term-Python-interpreter">Python interpreter<a class="headerlink" href="#term-Python-interpreter" title="Link to this term">¶</a></dt><dd><p>The piece of software which interprets and executes Python commands.</p>
</dd>
<dt id="term-scope">scope<a class="headerlink" href="#term-scope" title="Link to this term">¶</a></dt><dd><p>The scope of a name is the section of code for which that name is valid.</p>
</dd>
<dt id="term-script">script<a class="headerlink" href="#term-script" title="Link to this term">¶</a></dt><dt id="term-program">program<a class="headerlink" href="#term-program" title="Link to this term">¶</a></dt><dd><p>A text file containing a sequence of Python statements to be
executed. In Python, program and script are synonymous.</p>
</dd>
</dl>
</div></blockquote>
</section>
<section id="exercises">
<span id="programs-in-files-exercises"></span><h2><span class="section-number">2.8. </span>Exercises<a class="headerlink" href="#exercises" title="Link to this heading">¶</a></h2>
<p>Before attempting the exercises, ensure that you have obtained the software
tools described in <a class="reference internal" href="1_introduction.html#tools"><span class="std std-numref">Section 1.1</span></a> and set up a working folder and
<a class="reference internal" href="1_introduction.html#term-virtual-environment"><span class="xref std std-term">virtual environment</span></a> as described in <a class="reference internal" href="1_introduction.html#create-venv"><span class="std std-numref">Section 1.2</span></a>. If you’re not
already familiar with Git and GitHub then you will also need to work through
<a class="reference internal" href="a2_git.html#git"><span class="std std-numref">Appendix 2</span></a> to learn enough to do the exercises.</p>
<div class="proof proof-type-exercise" id="id12">
<span id="course-repo"></span>
<div class="proof-title">
<span class="proof-type">Exercise 2.1</span>
</div><div class="proof-content">
<p>Visit the <a class="reference external" href="https://github.com/object-oriented-python/object-oriented-programming">GitHub repository for this book</a>.
Clone that git repository into your course folder, and install the Python
package it contains into your virtual environment. Check that it has
installed correctly by installing Pytest, and running:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pytest<span class="w"> </span>tests/test_fibonacci.py
</pre></div>
</div>
<p>You could also run IPython, import <a class="reference internal" href="fibonacci.html#module-fibonacci" title="fibonacci"><code class="xref py py-mod docutils literal notranslate"><span class="pre">fibonacci</span></code></a> and try out
<a class="reference internal" href="fibonacci.html#fibonacci.fibonacci.fib" title="fibonacci.fibonacci.fib"><code class="xref py py-func docutils literal notranslate"><span class="pre">fibonacci.fib</span></code></a> yourself.</p>
</div></div><div class="proof proof-type-exercise" id="id13">
<div class="proof-title">
<span class="proof-type">Exercise 2.2</span>
</div><div class="proof-content">
<p>Using the information on the <a class="reference external" href="https://object-oriented-python.github.io/edition3/exercises.html">book website</a>
create your chapter 2 exercise repository for this module and clone it
into your working folder. The exercise repository just contains a
<code class="file docutils literal notranslate"><span class="pre">README</span></code> and some tests. Your job in the following exercises will be
to populate it with the remaining content.</p>
</div></div><div class="proof proof-type-exercise" id="id14">
<div class="proof-title">
<span class="proof-type">Exercise 2.3</span>
</div><div class="proof-content">
<p>In your week 2 exercise repository, create a new Python <a class="reference internal" href="#term-package"><span class="xref std std-term">package</span></a>
named <code class="xref py py-mod docutils literal notranslate"><span class="pre">math_utils</span></code> containing a <a class="reference internal" href="#term-module"><span class="xref std std-term">module</span></a> called <code class="xref py py-mod docutils literal notranslate"><span class="pre">primes</span></code>.
In the <code class="xref py py-mod docutils literal notranslate"><span class="pre">primes</span></code> module define a function <code class="xref py py-func docutils literal notranslate"><span class="pre">isprime()</span></code> which takes
in a single integer argument and returns <a class="reference external" href="https://docs.python.org/3/library/constants.html#True" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">True</span></code></a> or <a class="reference external" href="https://docs.python.org/3/library/constants.html#False" title="(in Python v3.14)"><code class="xref py py-obj docutils literal notranslate"><span class="pre">False</span></code></a> depending on
whether or not the argument is prime. There is no need use a sophisticated
algorithm, simply checking whether the number is zero modulo any of the
integers less than its square root will be fine. Test your code by running
the following in the exercise repository:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(PoP_venv)</span> <span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>pytest<span class="w"> </span>tests/test_exercise_2_3.py
</pre></div>
</div>
<p>Then push your code to GitHub and check that the tests pass there too.</p>
<div class="admonition hint">
<p class="admonition-title">Hint</p>
<p>The Python modulo operator is <code class="xref py py-obj docutils literal notranslate"><span class="pre">%</span></code>. For example:</p>
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="gp">In [1]: </span><span class="mi">4</span> <span class="o">%</span> <span class="mi">3</span>
<span class="gh">Out[1]: </span><span class="go">1</span>
</pre></div>
</div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>After this and every exercise in which you write code, ensure that you
add any new files to Git, commit all of your changes, and push to
GitHub. Then ensure that the tests pass on GitHub. For more information
about how to do any of these, refer to <a class="reference internal" href="a2_git.html#git"><span class="std std-numref">Appendix 2</span></a>.</p>
</div>
</div></div><div class="proof proof-type-exercise" id="id15">
<div class="proof-title">
<span class="proof-type">Exercise 2.4</span>
</div><div class="proof-content">
<p>Following <a class="reference internal" href="#installable-packages"><span class="std std-numref">Section 2.4.2</span></a>, create a <code class="file docutils literal notranslate"><span class="pre">pyproject.toml</span></code>
file in your exercise repository, so that the <code class="xref py py-mod docutils literal notranslate"><span class="pre">math_utils</span></code>
<a class="reference internal" href="#term-package"><span class="xref std std-term">package</span></a> is installable.</p>
<p>Pytest can’t easily test installability for you, so once you have managed to
install your package yourself, commit and push to GitHub to check that the
tests there are also able to install your package.</p>
</div></div><div class="proof proof-type-exercise" id="id16">
<div class="proof-title">
<span class="proof-type">Exercise 2.5</span>
</div><div class="proof-content">
<p>Add an <a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#import" title="(in Python v3.14)"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">import</span></code></a> to <code class="file docutils literal notranslate"><span class="pre">math_utils.__init__.py</span></code> so that the following
code will work:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">math_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">isprime</span>
</pre></div>
</div>
</div></div><p class="rubric">Footnotes</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="peters" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id2">1</a><span class="fn-bracket">]</span></span>