0% found this document useful (0 votes)
33 views

Python Distilled 1st edition - eBook PDF instant download

The document provides information about the eBook 'Python Distilled' and various other Python-related eBooks available for download. It includes links to download these eBooks and mentions the author's name, David M. Beazley. Additionally, it outlines the contents of 'Python Distilled', covering fundamental Python concepts and programming techniques.

Uploaded by

shutyprawldk
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views

Python Distilled 1st edition - eBook PDF instant download

The document provides information about the eBook 'Python Distilled' and various other Python-related eBooks available for download. It includes links to download these eBooks and mentions the author's name, David M. Beazley. Additionally, it outlines the contents of 'Python Distilled', covering fundamental Python concepts and programming techniques.

Uploaded by

shutyprawldk
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 81

Python Distilled 1st edition - eBook PDF

download

https://ebooksecure.com/download/python-distilled-ebook-pdf/

Download full version ebook from https://ebooksecure.com


We believe these products will be a great fit for you. Click
the link to download now, or visit ebooksecure.com
to discover even more!

(eBook PDF) Building Python Programs 1st Edition

http://ebooksecure.com/product/ebook-pdf-building-python-
programs-1st-edition/

Python For Dummies 1st Edition - PDF Version

http://ebooksecure.com/product/python-for-dummies-1st-edition-
pdf-version/

Problem Solving and Python Programming 1st edition -


eBook PDF

https://ebooksecure.com/download/problem-solving-and-python-
programming-ebook-pdf/

Programming and Problem Solving with Python 1st Edition


- eBook PDF

https://ebooksecure.com/download/programming-and-problem-solving-
with-python-ebook-pdf/
Data Structures & Algorithms in Python 1st Edition John
Canning - eBook PDF

https://ebooksecure.com/download/data-structures-algorithms-in-
python-ebook-pdf-2/

Data Structures & Algorithms in Python 1st Edition John


Canning - eBook PDF

https://ebooksecure.com/download/data-structures-algorithms-in-
python-ebook-pdf/

R and Python for Oceanographers: A Practical Guide with


Applications 1st Edition- eBook PDF

https://ebooksecure.com/download/r-and-python-for-oceanographers-
a-practical-guide-with-applications-ebook-pdf/

(eBook PDF) Starting Out with Python (4th Edition)

http://ebooksecure.com/product/ebook-pdf-starting-out-with-
python-4th-edition/

(eBook PDF) Python Programming in Context 3rd Edition

http://ebooksecure.com/product/ebook-pdf-python-programming-in-
context-3rd-edition/
Python Distilled
This page intentionally left blank
Python Distilled

David M. Beazley

Boston • Columbus • New York • San Francisco • Amsterdam • Cape Town


Dubai • London • Madrid • Milan • Munich • Paris • Montreal • Toronto • Delhi • Mexico City
São Paulo • Sydney • Hong Kong • Seoul • Singapore • Taipei • Tokyo
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and the publisher was aware of a trademark
claim, the designations have been printed with initial capital letters or in all capitals.

The author and publisher have taken care in the preparation of this book, but make no expressed or
implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed
for incidental or consequential damages in connection with or arising out of the use of the information or
programs contained herein.

For information about buying this title in bulk quantities, or for special sales opportunities (which may
include electronic versions; custom cover designs; and content particular to your business, training goals,
marketing focus, or branding interests), please contact our corporate sales department
at corpsales@pearsoned.com or (800) 382-3419.

For government sales inquiries, please contact governmentsales@pearsoned.com.

For questions about sales outside the U.S., please contact intlcs@pearson.com.

Visit us on the Web: informit.com/aw

Library of Congress Control Number: 2021943288

Copyright © 2022 Pearson Education, Inc.

Cover illustration by EHStockphoto/Shutterstock

All rights reserved. This publication is protected by copyright, and permission must be obtained from the
publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or
by any means, electronic, mechanical, photocopying, recording, or likewise. For information regarding
permissions, request forms and the appropriate contacts within the Pearson Education Global Rights &
Permissions Department, please visit www.pearson.com/permissions.

ISBN-13: 978-0-13-417327-6
ISBN-10: 0-13-417327-9

ScoutAutomatedPrintCode
Contents

Preface xiii

1 Python Basics 1
1.1 Running Python 1
1.2 Python Programs 2
1.3 Primitives, Variables, and
Expressions 3
1.4 Arithmetic Operators 5
1.5 Conditionals and Control Flow 7
1.6 Text Strings 9
1.7 File Input and Output 12
1.8 Lists 13
1.9 Tuples 15
1.10 Sets 17
1.11 Dictionaries 18
1.12 Iteration and Looping 21
1.13 Functions 22
1.14 Exceptions 24
1.15 Program Termination 26
1.16 Objects and Classes 26
1.17 Modules 30
1.18 Script Writing 32
1.19 Packages 33
1.20 Structuring an Application 34
1.21 Managing Third-Party Packages 35
1.22 Python: It Fits Your Brain 36

2 Operators, Expressions, and Data


Manipulation 37
2.1 Literals 37
2.2 Expressions and Locations 38
2.3 Standard Operators 39
2.4 In-Place Assignment 41
2.5 Object Comparison 42
2.6 Ordered Comparison Operators 42
vi Contents

2.7 Boolean Expressions and Truth


Values 43
2.8 Conditional Expressions 44
2.9 Operations Involving Iterables 45
2.10 Operations on Sequences 47
2.11 Operations on Mutable
Sequences 49
2.12 Operations on Sets 50
2.13 Operations on Mappings 51
2.14 List, Set, and Dictionary
Comprehensions 52
2.15 Generator Expressions 54
2.16 The Attribute (.) Operator 56
2.17 The Function Call () Operator 56
2.18 Order of Evaluation 56
2.19 Final Words: The Secret Life of
Data 58

3 Program Structure and Control


Flow 59
3.1 Program Structure and
Execution 59
3.2 Conditional Execution 59
3.3 Loops and Iteration 60
3.4 Exceptions 64
3.4.1 The Exception
Hierarchy 67
3.4.2 Exceptions and Control
Flow 68
3.4.3 Defining New
Exceptions 69
3.4.4 Chained Exceptions 70
3.4.5 Exception
Tracebacks 73
3.4.6 Exception Handling
Advice 73
3.5 Context Managers and the with
Statement 75
3.6 Assertions and __debug__ 77
3.7 Final Words 78
Contents vii

4 Objects, Types, and Protocols 79


4.1 Essential Concepts 79
4.2 Object Identity and Type 80
4.3 Reference Counting and Garbage
Collection 81
4.4 References and Copies 83
4.5 Object Representation and Printing 84
4.6 First-Class Objects 85
4.7 Using None for Optional or Missing
Data 87
4.8 Object Protocols and Data
Abstraction 87
4.9 Object Protocol 89
4.10 Number Protocol 90
4.11 Comparison Protocol 92
4.12 Conversion Protocols 94
4.13 Container Protocol 95
4.14 Iteration Protocol 97
4.15 Attribute Protocol 98
4.16 Function Protocol 98
4.17 Context Manager Protocol 99
4.18 Final Words: On Being Pythonic 99

5 Functions 101
5.1 Function Definitions 101
5.2 Default Arguments 101
5.3 Variadic Arguments 102
5.4 Keyword Arguments 103
5.5 Variadic Keyword Arguments 104
5.6 Functions Accepting All Inputs 104
5.7 Positional-Only Arguments 105
5.8 Names, Documentation Strings, and Type
Hints 106
5.9 Function Application and Parameter
Passing 107
5.10 Return Values 109
5.11 Error Handling 110
5.12 Scoping Rules 111
5.13 Recursion 114
viii Contents

5.14 The lambda Expression 114


5.15 Higher-Order Functions 115
5.16 Argument Passing in Callback
Functions 118
5.17 Returning Results from
Callbacks 121
5.18 Decorators 124
5.19 Map, Filter, and Reduce 127
5.20 Function Introspection, Attributes,
and Signatures 129
5.21 Environment Inspection 131
5.22 Dynamic Code Execution and
Creation 133
5.23 Asynchronous Functions and
await 135
5.24 Final Words: Thoughts on Functions
and Composition 137

6 Generators 139
6.1 Generators and yield 139
6.2 Restartable Generators 142
6.3 Generator Delegation 142
6.4 Using Generators in Practice 144
6.5 Enhanced Generators and yield
Expressions 146
6.6 Applications of Enhanced
Generators 148
6.7 Generators and the Bridge to
Awaiting 151
6.8 Final Words: A Brief History of
Generators and Looking
Forward 152

7 Classes and Object-Oriented


Programming 153
7.1 Objects 153
7.2 The class Statement 154
7.3 Instances 155
7.4 Attribute Access 156
7.5 Scoping Rules 158
Contents ix

7.6 Operator Overloading and Protocols 159


7.7 Inheritance 160
7.8 Avoiding Inheritance via Composition 163
7.9 Avoiding Inheritance via Functions 166
7.10 Dynamic Binding and Duck Typing 167
7.11 The Danger of Inheriting from Built-in
Types 167
7.12 Class Variables and Methods 169
7.13 Static Methods 173
7.14 A Word about Design Patterns 176
7.15 Data Encapsulation and Private
Attributes 176
7.16 Type Hinting 179
7.17 Properties 180
7.18 Types, Interfaces, and Abstract Base
Classes 183
7.19 Multiple Inheritance, Interfaces, and
Mixins 187
7.20 Type-Based Dispatch 193
7.21 Class Decorators 194
7.22 Supervised Inheritance 197
7.23 The Object Life Cycle and Memory
Management 199
7.24 Weak References 204
7.25 Internal Object Representation and
Attribute Binding 206
7.26 Proxies, Wrappers, and Delegation 208
7.27 Reducing Memory Use with
__slots__ 210
7.28 Descriptors 211
7.29 Class Definition Process 215
7.30 Dynamic Class Creation 216
7.31 Metaclasses 217
7.32 Built-in Objects for Instances and
Classes 222
7.33 Final Words: Keep It Simple 223

8 Modules and Packages 225


8.1 Modules and the import Statement 225
x Contents

8.2 Module Caching 227


8.3 Importing Selected Names from a
Module 228
8.4 Circular Imports 230
8.5 Module Reloading and
Unloading 232
8.6 Module Compilation 233
8.7 The Module Search Path 234
8.8 Execution as the Main Program 234
8.9 Packages 235
8.10 Imports Within a Package 237
8.11 Running a Package Submodule as a
Script 238
8.12 Controlling the Package
Namespace 239
8.13 Controlling Package Exports 240
8.14 Package Data 241
8.15 Module Objects 242
8.16 Deploying Python Packages 243
8.17 The Penultimate Word: Start with a
Package 244
8.18 The Final Word: Keep It Simple 245

9 Input and Output 247


9.1 Data Representation 247
9.2 Text Encoding and Decoding 248
9.3 Text and Byte Formatting 250
9.4 Reading Command-Line
Options 254
9.5 Environment Variables 256
9.6 Files and File Objects 256
9.6.1 Filenames 257
9.6.2 File Modes 258
9.6.3 I/O Buffering 258
9.6.4 Text Mode Encoding 259
9.6.5 Text-Mode Line
Handling 260
9.7 I/O Abstraction Layers 260
9.7.1 File Methods 261
Contents xi

9.8 Standard Input, Output, and Error 263


9.9 Directories 264
9.10 The print() function 265
9.11 Generating Output 265
9.12 Consuming Input 266
9.13 Object Serialization 268
9.14 Blocking Operations and
Concurrency 269
9.14.1 Nonblocking I/O 270
9.14.2 I/O Polling 271
9.14.3 Threads 271
9.14.4 Concurrent Execution with
asyncio 272
9.15 Standard Library Modules 273
9.15.1 asyncio Module 273
9.15.2 binascii Module 274
9.15.3 cgi Module 275
9.15.4 configparser Module 276
9.15.5 csv Module 276
9.15.6 errno Module 277
9.15.7 fcntl Module 278
9.15.8 hashlib Module 278
9.15.9 http Package 279
9.15.10 io Module 279
9.15.11 json Module 280
9.15.12 logging Module 280
9.15.13 os Module 281
9.15.14 os.path Module 281
9.15.15 pathlib Module 282
9.15.16 re Module 283
9.15.17 shutil Module 284
9.15.18 select Module 284
9.15.19 smtplib Module 285
9.15.20 socket Module 286
9.15.21 struct Module 288
9.15.22 subprocess Module 288
9.15.23 tempfile Module 289
9.15.24 textwrap Module 290
xii Contents

9.15.25 threading Module 291


9.15.26 time Module 293
9.15.27 urllib Package 293
9.15.28 unicodedata
Module 294
9.15.29 xml Package 295
9.16 Final Words 296

10 Built-in Functions and Standard


Library 297
10.1 Built-in Functions 297
10.2 Built-in Exceptions 314
10.2.1 Exception Base
Classes 314
10.2.2 Exception Attributes 314
10.2.3 Predefined Exception
Classes 315
10.3 Standard Library 318
10.3.1 collections
Module 318
10.3.2 datetime Module 318
10.3.3 itertools Module 318
10.3.4 inspect Module 318
10.3.5 math Module 318
10.3.6 os Module 319
10.3.7 random Module 319
10.3.8 re Module 319
10.3.9 shutil Module 319
10.3.10 statistics
Module 319
10.3.11 sys Module 319
10.3.12 time Module 319
10.3.13 turtle Module 319
10.3.14 unittest Module 319
10.4 Final Words: Use the Built-Ins 320

Index 321
Preface

More than 20 years have passed since I authored the Python Essential Reference. At that time,
Python was a much smaller language and it came with a useful set of batteries in its
standard library. It was something that could mostly fit in your brain. The Essential Reference
reflected that era. It was a small book that you could take with you to write some Python
code on a desert island or inside a secret vault. Over the three subsequent revisions, the
Essential Reference stuck with this vision of being a compact but complete language
reference —because if you’re going to code in Python on vacation, why not use all of it?
Today, more than a decade since the publication of the last edition, the Python world is
much different. No longer a niche language, Python has become one of the most popular
programming languages in the world. Python programmers also have a wealth of
information at their fingertips in the form of advanced editors, IDEs, notebooks, web
pages, and more. In fact, there’s probably little need to consult a reference book when
almost any reference material you might want can be conjured to appear before your eyes
with the touch of a few keys.
If anything, the ease of information retrieval and the scale of the Python universe
presents a different kind of challenge. If you’re just starting to learn or need to solve a new
problem, it can be overwhelming to know where to begin. It can also be difficult to
separate the features of various tools from the core language itself. These kinds of problems
are the rationale for this book.
Python Distilled is a book about programming in Python. It’s not trying to document
everything that’s possible or has been done in Python. Its focus is on presenting a modern
yet curated (or distilled) core of the language. It has been informed by my years of teaching
Python to scientists, engineers, and software professionals. However, it’s also a product of
writing software libraries, pushing the edges of what makes Python tick, and finding out
what’s most useful.
For the most part, the book focuses on Python programming itself. This includes
abstraction techniques, program structure, data, functions, objects, modules, and so
forth— topics that will well serve programmers working on Python projects of any size.
Pure reference material that can be easily obtained via an IDE (such as lists of functions,
names of commands, arguments, etc.) is generally omitted. I’ve also made a conscious
choice to not describe the fast-changing world of Python tooling —editors, IDEs,
deployment, and related matters.
Perhaps controversially, I don’t generally focus on language features related to large-scale
software project management. Python is sometimes used for big and serious things—
comprised of millions upon millions of lines of code. Such applications require specialized
tooling, design, and features. They also involve committees, and meetings, and decisions
to be made about very important matters. All this is too much for this small book. But
xiv Preface

perhaps the honest answer is that I don’t use Python to write such applications— and
neither should you. At least not as a hobby.
In writing a book, there is always a cut-off for the ever-evolving language features. This
book was written during the era of Python 3.9. As such, it does not include some of the
major additions planned for later releases — for example, structural pattern matching.
That’s a topic for a different time and place.
Last, but not least, I think it’s important that programming remains fun. I hope that my
book will not only help you become a productive Python programmer but also capture
some of the magic that has inspired people to use Python for exploring the stars, flying
helicopters on Mars, and spraying squirrels with a water cannon in the backyard.

Acknowledgments
I’d like to thank the technical reviewers, Shawn Brown, Sophie Tabac, and Pete Fein, for
their helpful comments. I’d also like to thank my long-time editor Debra Williams Cauley
for her work on this and past projects. The many students who have taken my classes have
had a major if indirect impact on the topics covered in this book. Last, but not least, I’d
like to thank Paula, Thomas, and Lewis for their support and love.

About the Author


David Beazley is the author of the Python Essential Reference, Fourth Edition
(Addison-Wesley, 2010) and Python Cookbook, Third Edition (O’Reilly, 2013). He
currently teaches advanced computer science courses through his company Dabeaz LLC
( www.dabeaz.com ). He’s been using, writing, speaking, and teaching about Python
since 1996.
1
Python Basics

This chapter gives an overview of the core of the Python language. It covers variables,
data types, expressions, control flow, functions, classes, and input/output. The chapter
concludes with a discussion of modules, script writing, packages, and a few tips on
organizing larger programs. This chapter is not trying to provide comprehensive coverage
of every feature, nor does it concern itself with all of the tooling that might surround a
larger Python project. However, experienced programmers should be able to extrapolate
from the material here to write more advanced programs. Newcomers are encouraged to
try the examples in a simple environment, such as a terminal window and a basic text
editor.

1.1 Running Python


Python programs are executed by an interpreter. There are many different environments
in which the Python interpreter might run —an IDE, a browser, or a terminal window.
However, underneath all that, the core of the interpreter is a text-based application that
can be started by typing python in a command shell such as bash. Since Python 2 and
Python 3 might both be installed on the same machine, you might need to type python2
or python3 to pick a version. This book assumes Python 3.8 or newer.
When the interpreter starts, a prompt appears where you can type programs into a
so-called “read-evaluation-print loop” (or REPL). For example, in the following output,
the interpreter displays its copyright message and presents the user with the >>> prompt, at
which the user types a familiar “Hello World” program:

Python 3.8.0 (default, Feb 3 2019, 05:53:21)


[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print('Hello World')
Hello World
>>>
2 Chapter 1 Python Basics

Certain environments may display a different prompt. The following output is from
ipython (an alternate shell for Python):

Python 3.8.0 (default, Feb 4, 2019, 07:39:16)


Type 'copyright', 'credits' or 'license' for more information
IPython 6.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: print('Hello World')


Hello World

In [2]:

Regardless of the exact form of output you see, the underlying principle is the same.
You type a command, it runs, and you immediately see the output.
Python’s interactive mode is one of its most useful features because you can type any
valid statement and immediately see the result. This is useful for debugging and
experimentation. Many people, including the author, use interactive Python as their
desktop calculator. For example:
>>> 6000 + 4523.50 + 134.25
10657.75
>>> _ + 8192.75
18850.5
>>>

When you use Python interactively, the variable _ holds the result of the last operation.
This is useful if you want to use that result in subsequent statements. This variable only
gets defined when working interactively, so don’t use it in saved programs.
You can exit the interactive interpreter by typing quit() or the EOF (end of file)
character. On UNIX, EOF is Ctrl+D; on Windows, it’s Ctrl+Z.

1.2 Python Programs


If you want to create a program that you can run repeatedly, put statements in a text file.
For example:
# hello.py
print('Hello World')

Python source files are UTF-8-encoded text files that normally have a .py suffix. The
# character denotes a comment that extends to the end of the line. International (Unicode)
characters can be freely used in the source code as long as you use the UTF-8 encoding
(this is the default in most editors, but it never hurts to check your editor settings if you’re
unsure).
1.3 Primitives, Variables, and Expressions 3

To execute the hello.py file, provide the filename to the interpreter as follows:
shell % python3 hello.py
Hello World
shell %

It is common to use #! to specify the interpreter on the first line of a program, like this:
#!/usr/bin/env python3
print('Hello World')

On UNIX, if you give this file execute permissions (for example, by chmod +x
hello.py), you can run the program by typing hello.py into your shell.
On Windows, you can double-click on a .py file or type the name of the program into
the Run command on the Windows Start menu to launch it. The #! line, if given, is used
to pick the interpreter version (Python 2 versus 3). Execution of a program might take
place in a console window that disappears immediately after the program completes—
often before you can read its output. For debugging, it’s better to run the program within
a Python development environment.
The interpreter runs statements in order until it reaches the end of the input file. At
that point, the program terminates and Python exits.

1.3 Primitives, Variables, and Expressions


Python provides a collection of primitive types such as integers, floats, and strings:
42 # int
4.2 # float
'forty-two' # str
True # bool

A variable is a name that refers to a value. A value represents an object of some type:
x = 42

Sometimes you might see a type explicitly attached to a name. For example:
x: int = 42

The type is merely a hint to improve code readability. It can be used by third-party
code-checking tools. Otherwise, it is completely ignored. It does not prevent you from
assigning a different kind of value later.
An expression is a combination of primitives, names, and operators that produces a
value:
2 + 3 * 4 # -> 14
4 Chapter 1 Python Basics

The following program uses variables and expressions to perform a compound-interest


calculation:
# interest.py

principal = 1000 # Initial amount


rate = 0.05 # Interest rate
numyears = 5 # Number of years
year = 1
while year <= numyears:
principal = principal * (1 + rate)
print(year, principal)
year += 1

When executed, it produces the following output:


1 1050.0
2 1102.5
3 1157.625
4 1215.5062500000001
5 1276.2815625000003

The while statement tests the conditional expression that immediately follows. If the
tested condition is true, the body of the while statement executes. The condition is
then retested and the body executed again until the condition becomes false. The body
of the loop is denoted by indentation. Thus, the three statements following while in
interest.py execute on each iteration. Python doesn’t specify the amount of required
indentation, as long as it’s consistent within a block. It is most common to use four spaces
per indentation level.
One problem with the interest.py program is that the output isn’t very pretty. To
make it better, you could right-align the columns and limit the precision of principal
to two digits. Change the print() function to use a so-called f-string like this:
print(f'{year:>3d} {principal:0.2f}')

In the f-string, variable names and expressions can be evaluated by enclosing them in
curly braces. Optionally, each substitution can have a formatting specifier attached to it.
'>3d' means a three-digit decimal number, right aligned. '0.2f' means a floating-point
number with two decimal places of accuracy. More information about these formatting
codes can be found in Chapter 9.
Now the output of the program looks like this:
1 1050.00
2 1102.50
3 1157.62
4 1215.51
5 1276.28
1.4 Arithmetic Operators 5

1.4 Arithmetic Operators


Python has a standard set of mathematical operators, shown in Table 1.1. These operators
have the same meaning they do in most other programming languages.

Table 1.1 Arithmetic Operators

Operation Description

x + y Addition
x - y Subtraction
x * y Multiplication
x / y Division
x // y Truncating division
x ** y Power (x to the y power)
x % y Modulo (x mod y). Remainder.
–x Unary minus
+x Unary plus

The division operator (/) produces a floating-point number when applied to integers.
Therefore, 7/4 is 1.75. The truncating division operator //, also known as floor division,
truncates the result to an integer and works with both integers and floating-point
numbers. The modulo operator returns the remainder of the division x // y. For
example, 7 % 4 is 3. For floating-point numbers, the modulo operator returns the
floating-point remainder of x // y, which is x – (x // y) * y.
In addition, the built-in functions in Table 1.2 provide a few more commonly used
numerical operations.

Table 1.2 Common Mathematic Functions


Function Description

abs(x) Absolute value


divmod(x,y) Returns (x // y, x % y)
pow(x,y [,modulo]) Returns (x ** y) % modulo
round(x,[n]) Rounds to the nearest multiple of 10 to the nth power.

The round() function implements “banker’s rounding.” If the value being rounded is
equally close to two multiples, it is rounded to the nearest even multiple (for example, 0.5
is rounded to 0.0, and 1.5 is rounded to 2.0).
Integers provide a few additional operators to support bit manipulation, shown in
Table 1.3.
6 Chapter 1 Python Basics

Table 1.3 Bit Manipulation Operators

Operation Description

x << y Left shift


x >> y Right shift
x & y Bitwise and
x | y Bitwise or
x ^ y Bitwise xor (exclusive or)
~x Bitwise negation

One would commonly use these with binary integers. For example:
a = 0b11001001
mask = 0b11110000
x = (a & mask) >> 4 # x = 0b1100 (12)

In this example, 0b11001001 is how you write an integer value in binary. You could
have written it as decimal 201 or hexadecimal 0xc9, but if you’re fiddling with bits, binary
makes it easier to visualize what you’re doing.
The semantics of the bitwise operators assumes that the integers use a two’s
complement binary representation and that the sign bit is infinitely extended to the left.
Some care is required if you are working with raw bit patterns that are intended to map to
native integers on the hardware. This is because Python does not truncate the bits or allow
values to overflow — instead, the result will grow arbitrarily large in magnitude. It’s up to
you to make sure the result is properly sized or truncated if needed.
To compare numbers, use the comparison operators in Table 1.4.

Table 1.4 Comparison Operators

Operation Description

x == y Equal to
x != y Not equal to
x < y Less than
x > y Greater than
x >= y Greater than or equal to
x <= y Less than or equal to

The result of a comparison is a Boolean value True or False.


The and, or, and not operators (not to be confused with the bit-manipulation
operators above) can form more complex Boolean expressions. The behavior of these
operators is as shown in Table 1.5.
A value is considered false if it is literally False, None, numerically zero, or empty.
Otherwise, it’s considered true.
1.5 Conditionals and Control Flow 7

Table 1.5 Logical Operators

Operator Description

x or y If x is false, return y; otherwise, return x.


x and y If x is false, return x; otherwise, return y.
not x If x is false, return True; otherwise, return False.

It is common to write an expression that updates a value. For example:


x = x + 1
y = y * n

For these, you can write the following shortened operation instead:
x += 1
y *= n

This shortened form of update can be used with any of the +, -, *, **, /, //, %, &, |, ^,
<<, >>operators. Python does not have increment (++) or decrement (--) operators found
in some other languages.

1.5 Conditionals and Control Flow


The while, if and else statements are used for looping and conditional code execution.
Here’s an example:
if a < b:
print('Computer says Yes')
else:
print('Computer says No')

The bodies of the if and else clauses are denoted by indentation. The else clause is
optional. To create an empty clause, use the pass statement, as follows:
if a < b:
pass # Do nothing
else:
print('Computer says No')

To handle multiple-test cases, use the elif statement:


if suffix == '.htm':
content = 'text/html'
elif suffix == '.jpg':
content = 'image/jpeg'
8 Chapter 1 Python Basics

elif suffix == '.png':


content = 'image/png'
else:
raise RuntimeError(f'Unknown content type {suffix!r}')

If you are assigning a value in combination with a test, use a conditional expression:
maxval = a if a > b else b

This is the same as the longer:


if a > b:
maxval = a
else:
maxval = b

Sometimes, you may see the assignment of a variable and a conditional combined
together using the := operator. This is known as an assignment expression (or more
colloquially as the “walrus operator” because := looks like a walrus tipped over on its
side —presumably playing dead). For example:
x = 0
while (x := x + 1) < 10: # Prints 1, 2, 3, ..., 9
print(x)

The parentheses used to surround an assignment expression are always required.


The break statement can be used to abort a loop early. It only applies to the innermost
loop. For example:
x = 0
while x < 10:
if x == 5:
break # Stops the loop. Moves to Done below
print(x)
x += 1

print('Done')

The continue statement skips the rest of the loop body and goes back to the top of the
loop. For example:
x = 0
while x < 10:
x += 1
if x == 5:
continue # Skips the print(x). Goes back to loop start.
print(x)

print('Done')
1.6 Text Strings 9

1.6 Text Strings


To define a string literal, enclose it in single, double, or triple quotes as follows:

a = 'Hello World'
b = "Python is groovy"
c = '''Computer says no.'''
d = """Computer still says no."""

The same type of quote used to start a string must be used to terminate it. Triple-
quoted strings capture all the text until the terminating triple quote — as opposed to single-
and double-quoted strings which must be specified on one logical line. Triple-quoted
strings are useful when the contents of a string literal span multiple lines of text:
print('''Content-type: text/html

<h1> Hello World </h1>


Click <a href="http://www.python.org">here</a>.
''')

Immediately adjacent string literals are concatenated into a single string. Thus, the
above example could also be written as:
print(
'Content-type: text/html\n'
'\n'
'<h1> Hello World </h1>\n'
'Clock <a href="http://www.python.org">here</a>\n'
)

If the opening quotation mark of a string is prefaced by an f, escaped expressions


within a string are evaluated. For example, in earlier examples, the following statement was
used to output values of a calculation:
print(f'{year:>3d} {principal:0.2f}')

Although this is only using simple variable names, any valid expression can appear. For
example:
base_year = 2020
...
print(f'{base_year + year:>4d} {principal:0.2f}')

As an alternative to f-strings, the format() method and % operator are also sometimes
used to format strings. For example:
print('{0:>3d} {1:0.2f}'.format(year, principal))
print('%3d %0.2f' % (year, principal))
10 Chapter 1 Python Basics

More information about string formatting is found in Chapter 9.


Strings are stored as sequences of Unicode characters indexed by integers, starting at
zero. Negative indices index from the end of the string. The length of a string s is
computed using len(s). To extract a single character, use the indexing operator s[i]
where i is the index.
a = 'Hello World'
print(len(a)) # 11
b = a[4] # b = 'o'
c = a[-1] # c = 'd'

To extract a substring, use the slicing operator s[i:j]. It extracts all characters from s
whose index k is in the range i <= k < j. If either index is omitted, the beginning or end
of the string is assumed, respectively:
c = a[:5] # c = 'Hello'
d = a[6:] # d = 'World'
e = a[3:8] # e = 'lo Wo'
f = a[-5:] # f = 'World'

Strings have a variety of methods for manipulating their contents. For example, the
replace() method performs a simple text replacement:
g = a.replace('Hello', 'Hello Cruel') # f = 'Hello Cruel World'

Table 1.6 shows a few common string methods. Here and elsewhere, arguments
enclosed in square brackets are optional.

Table 1.6 Common String Methods

Method Description

s.endswith(prefix [,start [,end]]) Checks whether a string ends with prefix.


s.find(sub [, start [,end]]) Finds the first occurrence of the specified
substring sub or -1 if not found.
s.lower() Converts to lowercase.
s.replace(old, new [,maxreplace]) Replaces a substring.
s.split([sep [,maxsplit]]) Splits a string using sep as a delimiter.
maxsplit is the maximum number of splits to
perform.
s.startswith(prefix [,start [,end]]) Checks whether a string starts with prefix.
s.strip([chrs]) Removes leading and trailing whitespace or
characters supplied in chrs.
s.upper() Converts a string to uppercase.

Strings are concatenated with the plus (+) operator:


g = a + 'ly' # g = 'Hello Worldly'
1.6 Text Strings 11

Python never implicitly interprets the contents of a string as numerical data. Thus, +
always concatenates strings:
x = '37'
y = '42'
z = x + y # z = '3742' (String Concatenation)

To perform mathematical calculations, a string first has to be converted into a numeric


value using a function such as int() or float(). For example:
z = int(x) + int(y) # z = 79 (Integer Addition)

Non-string values can be converted into a string representation by using the str(),
repr(),or format() functions. Here’s an example:
s = 'The value of x is ' + str(x)
s = 'The value of x is ' + repr(x)
s = 'The value of x is ' + format(x, '4d')

Although str() and repr() both create strings, their output is often different. str()
produces the output that you get when you use the print() function, whereas repr()
creates a string that you type into a program to exactly represent the value of an object.
For example:
>>> s = 'hello\nworld'
>>> print(str(s))
hello
world
>>> print(repr(s))
'hello\nworld'
>>>

When debugging, use repr(s) to produce output because it shows you more
information about a value and its type.
The format() function is used to convert a single value to a string with a specific
formatting applied. For example:
>>> x = 12.34567
>>> format(x, '0.2f')
'12.35'
>>>

The format code given to format() is the same code you would use with f-strings
when producing formatted output. For example, the above code could be replaced by the
following:
>>> f'{x:0.2f}'
'12.35'
>>>
12 Chapter 1 Python Basics

1.7 File Input and Output


The following program opens a file and reads its contents line by line as text strings:
with open('data.txt') as file:
for line in file:
print(line, end='') # end='' omits the extra newline

The open() function returns a new file object. The with statement that precedes it
declares a block of statements (or context) where the file (file) is going to be used. Once
control leaves this block, the file is automatically closed. If you don’t use the with
statement, the code would need to look like this:
file = open('data.txt')
for line in file:
print(line, end='') # end='' omits the extra newline
file.close()

It’s easy to forget the extra step of calling close() so it’s better to use the with
statement and have the file closed for you.
The for loop iterates line-by-line over the file until no more data is available.
If you want to read the file in its entirety as a string, use the read() method like this:
with open('data.txt') as file:
data = file.read()

If you want to read a large file in chunks, give a size hint to the read() method as
follows:
with open('data.txt') as file:
while (chunk := file.read(10000)):
print(chunk, end='')

The := operator used in this example assigns to a variable and returns its value so that it
can be tested by the while loop to break out. When the end of a file is reached, read()
returns an empty string. An alternate way to write the above function is using break:
with open('data.txt') as file:
while True:
chunk = file.read(10000)
if not chunk:
break
print(chunk, end='')

To make the output of a program go to a file, supply a file argument to the print()
function:
with open('out.txt', 'wt') as out:
while year <= numyears:
1.8 Lists 13

principal = principal * (1 + rate)


print(f'{year:>3d} {principal:0.2f}', file=out)
year += 1

In addition, file objects support a write() method that can be used to write string data.
For example, the print() function in the previous example could have been written
this way:
out.write(f'{year:3d} {principal:0.2f}\n')

By default, files contain text encoded as UTF-8. If you’re working with a different text
encoding, use the extra encoding argument when opening the file. For example:
with open('data.txt', encoding='latin-1') as file:
data = file.read()

Sometimes you might want to read data typed interactively in the console. To do that,
use the input() function. For example:
name = input('Enter your name : ')
print('Hello', name)

The input() function returns all of the typed text up to the terminating newline,
which is not included.

1.8 Lists
Lists are an ordered collection of arbitrary objects. Create a list by enclosing values in
square brackets:
names = [ 'Dave', 'Paula', 'Thomas', 'Lewis' ]

Lists are indexed by integers, starting with zero. Use the indexing operator to access and
modify individual items of the list:
a = names[2] # Returns the third item of the list, 'Thomas'
names[2] = 'Tom' # Changes the third item to 'Tom'
print(names[-1]) # Print the last item ('Lewis')

To append new items to the end of a list, use the append() method:
names.append('Alex')

To insert an item in the list at a specific position, use the insert() method:
names.insert(2, 'Aya')

To iterate over the items in a list, use a for loop:


14 Chapter 1 Python Basics

for name in names:


print(name)

You can extract or reassign a portion of a list by using the slicing operator:
b = names[0:2] # b -> ['Dave', 'Paula']
c = names[2:] # c -> ['Aya', 'Tom', 'Lewis', 'Alex']
names[1] = 'Becky' # Replaces 'Paula' with 'Becky'
names[0:2] = ['Dave', 'Mark', 'Jeff'] # Replace the first two items
# with ['Dave','Mark','Jeff']

Use the plus (+) operator to concatenate lists:


a = ['x','y'] + ['z','z','y'] # Result is ['x','y','z','z','y']

An empty list is created in one of two ways:


names = [] # An empty list
names = list() # An empty list

Specifying [] for an empty list is more idiomatic. list is the name of the class
associated with the list type. It’s more common to see it used when performing
conversions of data to a list. For example:
letters = list('Dave') # letters = ['D', 'a', 'v', 'e']

Most of the time, all of the items in a list are of the same type (for example, a list of
numbers or a list of strings). However, lists can contain any mix of Python objects,
including other lists, as in the following example:
a = [1, 'Dave', 3.14, ['Mark', 7, 9, [100, 101]], 10]

Items contained in nested lists are accessed by applying more than one indexing
operation:
a[1] # Returns 'Dave'
a[3][2] # Returns 9
a[3][3][1] # Returns 101

The following program pcost.py illustrates how to read data into a list and perform a
simple calculation. In this example, lines are assumed to contain comma-separated values.
The program computes the sum of the product of two columns.
# pcost.py
#
# Reads input lines of the form 'NAME,SHARES,PRICE'.
# For example:
#
# SYM,123,456.78
1.9 Tuples 15

import sys
if len(sys.argv) != 2:
raise SystemExit(f'Usage: {sys.argv[0]} filename')

rows = []
with open(sys.argv[1], 'rt') as file:
for line in file:
rows.append(line.split(','))

# rows is a list of this form


# [
# ['SYM', '123', '456.78']
# ...
# ]

total = sum([ int(row[1]) * float(row[2]) for row in rows ])


print(f'Total cost: {total:0.2f}')

The first line of this program uses the import statement to load the sys module from
the Python library. This module is used to obtain command-line arguments which are
found in the list sys.argv. The initial check makes sure that a filename has been provided.
If not, a SystemExit exception is raised with a helpful error message. In this message,
sys.argv[0] inserts the name of the program that’s running.
The open() function uses the filename that was specified on the command line. The
for line in file loop is reading the file line by line. Each line is split into a small list
using the comma character as a delimiter. This list is appended to rows. The final result,
rows, is a list of lists —remember that a list can contain anything including other lists.
The expression [ int(row[1]) * float(row[2]) for row in rows ] constructs a new
list by looping over all of the lists in rows and computing the product of the second and
third items. This useful technique for constructing a list is known as a list comprehension.
The same computation could have been expressed more verbosely as follows:
values = []
for row in rows:
values.append(int(row[1]) * float(row[2]))
total = sum(values)

As a general rule, list comprehensions are a preferred technique for performing simple
calculations. The built-in sum() function computes the sum for all items in a sequence.

1.9 Tuples
To create simple data structures, you can pack a collection of values into an immutable
object known as a tuple. You create a tuple by enclosing a group of values in parentheses:
16 Chapter 1 Python Basics

holding = ('GOOG', 100, 490.10)


address = ('www.python.org', 80)

For completeness, 0- and 1-element tuples can be defined, but have special syntax:
a = () # 0-tuple (empty tuple)
b = (item,) # 1-tuple (note the trailing comma)

The values in a tuple can be extracted by numerical index just like a list. However, it is
more common to unpack tuples into a set of variables, like this:
name, shares, price = holding
host, port = address

Although tuples support most of the same operations as lists (such as indexing, slicing,
and concatenation), the elements of a tuple cannot be changed after creation — that is, you
cannot replace, delete, or append new elements to an existing tuple. A tuple is best viewed
as a single immutable object that consists of several parts, not as a collection of distinct
objects like a list.
Tuples and lists are often used together to represent data. For example, this program
shows how you might read a file containing columns of data separated by commas:
# File containing lines of the form ``name,shares,price"
filename = 'portfolio.csv'

portfolio = []
with open(filename) as file:
for line in file:
row = line.split(',')
name = row[0]
shares = int(row[1])
price = float(row[2])
holding = (name, shares, price)
portfolio.append(holding)

The resulting portfolio list created by this program looks like a two-dimensional array
of rows and columns. Each row is represented by a tuple and can be accessed as follows:
>>> portfolio[0]
('AA', 100, 32.2)
>>> portfolio[1]
('IBM', 50, 91.1)
>>>

Individual items of data can be accessed like this:


>>> portfolio[1][1]
50
1.10 Sets 17

>>> portfolio[1][2]
91.1
>>>

Here’s how to loop over all of the records and unpack fields into a set of variables:
total = 0.0
for name, shares, price in portfolio:
total += shares * price

Alternatively, you could use a list comprehension:


total = sum([shares * price for _, shares, price in portfolio])

When iterating over tuples, the variable _ can be used to indicate a discarded value. In
the above calculation, it means we’re ignoring the first item (the name).

1.10 Sets
A set is an unordered collection of unique objects. Sets are used to find distinct values or to
manage problems related to membership. To create a set, enclose a collection of values in
curly braces or give an existing collection of items to set(). For example:
names1 = { 'IBM', 'MSFT', 'AA' }
names2 = set(['IBM', 'MSFT', 'HPE', 'IBM', 'CAT'])

The elements of a set are typically restricted to immutable objects. For example, you can
make a set of numbers, strings, or tuples. However, you can’t make a set containing lists.
Most common objects will probably work with a set, however— when in doubt, try it.
Unlike lists and tuples, sets are unordered and cannot be indexed by numbers.
Moreover, the elements of a set are never duplicated. For example, if you inspect the value
of names2 from the preceding code, you get the following:
>>> names2
{'CAT', 'IBM', 'MSFT', 'HPE'}
>>>

Notice that 'IBM' only appears once. Also, the order of items can’t be predicted; the
output may vary from what’s shown. The order might even change between interpreter
runs on the same computer.
If working with existing data, you can also create a set using a set comprehension. For
example, this statement turns all of the stock names from the data in the previous section
into a set:
names = { s[0] for s in portfolio }
18 Chapter 1 Python Basics

To create an empty set, use set() with no arguments:


r = set() # Initially empty set

Sets support a standard collection of operations including union, intersection,


difference, and symmetric difference. Here’s an example:
a = t | s # Union {'MSFT', 'CAT', 'HPE', 'AA', 'IBM'}
b = t & s # Intersection {'IBM', 'MSFT'}
c = t - s # Difference { 'CAT', 'HPE' }
d = s - t # Difference { 'AA' }
e = t ^ s # Symmetric difference { 'CAT', 'HPE', 'AA' }

The difference operation s - t gives items in s that aren’t in t. The symmetric


difference s ^ t gives items that are in either s or t but not in both.
New items can be added to a set using add() or update():
t.add('DIS') # Add a single item
s.update({'JJ', 'GE', 'ACME'}) # Adds multiple items to s

An item can be removed using remove() or discard():


t.remove('IBM') # Remove 'IBM' or raise KeyError if absent.
s.discard('SCOX') # Remove 'SCOX' if it exists.

The difference between remove() and discard() is that discard() doesn’t raise an
exception if the item isn’t present.

1.11 Dictionaries
A dictionary is a mapping between keys and values. You create a dictionary by enclosing
the key-value pairs, each separated by a colon, in curly braces ({ }), like this:
s = {
'name' : 'GOOG',
'shares' : 100,
'price' : 490.10
}

To access members of a dictionary, use the indexing operator as follows:


name = s['name']
cost = s['shares'] * s['price']

Inserting or modifying objects works like this:


s['shares'] = 75
s['date'] = '2007-06-07'
1.11 Dictionaries 19

A dictionary is a useful way to define an object that consists of named fields. However,
dictionaries are also commonly used as a mapping for performing fast lookups on
unordered data. For example, here’s a dictionary of stock prices:

prices = {
'GOOG' : 490.1,
'AAPL' : 123.5,
'IBM' : 91.5,
'MSFT' : 52.13
}

Given such a dictionary, you can look up a price:


p = prices['IBM']

Dictionary membership is tested with the in operator:


if 'IBM' in prices:
p = prices['IBM']
else:
p = 0.0

This particular sequence of steps can also be performed more compactly using the
get() method:
p = prices.get('IBM', 0.0) # prices['IBM'] if it exists, else 0.0

Use the del statement to remove an element of a dictionary:


del prices['GOOG']

Although strings are the most common type of key, you can use many other Python
objects, including numbers and tuples. For example, tuples are often used to construct
composite or multipart keys:
prices = { }
prices[('IBM', '2015-02-03')] = 91.23
prices['IBM', '2015-02-04'] = 91.42 # Parens omitted

Any kind of object can be placed into a dictionary, including other dictionaries.
However, mutable data structures such as lists, sets, and dictionaries cannot be used as keys.
Dictionaries are often used as building blocks for various algorithms and data-handling
problems. One such problem is tabulation. For example, here’s how you could count the
total number of shares for each stock name in earlier data:
portfolio = [
('ACME', 50, 92.34),
('IBM', 75, 102.25),
('PHP', 40, 74.50),
20 Chapter 1 Python Basics

('IBM', 50, 124.75)


]

total_shares = { s[0]: 0 for s in portfolio }


for name, shares, _ in portfolio:
total_shares[name] += shares

# total_shares = {'IBM': 125, 'ACME': 50, 'PHP': 40}

In this example, { s[0]: 0 for s in portfolio } is an example of a dictionary


comprehension. It creates a dictionary of key-value pairs from another collection of data.
In this case, it’s making an initial dictionary mapping stock names to 0. The for loop that
follows iterates over the dictionary and adds up all of the held shares for each stock symbol.
Many common data processing tasks such as this one have already been implemented by
library modules. For example, the collections module has a Counter object that can be
used for this task:
from collections import Counter

total_shares = Counter()
for name, shares, _ in portfolio:
total_shares[name] += shares

# total_shares = Counter({'IBM': 125, 'ACME': 50, 'PHP': 40})

An empty dictionary is created in one of two ways:


prices = {} # An empty dict
prices = dict() # An empty dict

It is more idiomatic to use {} for an empty dictionary — although caution is required


since it might look like you are trying to create an empty set (use set() instead). dict() is
commonly used to create dictionaries from key-value values. For example:
pairs = [('IBM', 125), ('ACME', 50), ('PHP', 40)]
d = dict(pairs)

To obtain a list of dictionary keys, convert a dictionary to a list:


syms = list(prices) # syms = ['AAPL', 'MSFT', 'IBM', 'GOOG']

Alternatively, you can obtain the keys using dict.keys():


syms = prices.keys()

The difference between these two methods is that keys() returns a special “keys view”
that is attached to the dictionary and actively reflects changes made to the dictionary. For
example:
1.12 Iteration and Looping 21

>>> d = { 'x': 2, 'y':3 }


>>> k = d.keys()
>>> k
dict_keys(['x', 'y'])
>>> d['z'] = 4
>>> k
dict_keys(['x', 'y', 'z'])
>>>

The keys always appear in the same order as the items were initially inserted into the
dictionary. The list conversion above will preserve this order. This can be useful when dicts
are used to represent key-value data read from files and other data sources. The dictionary
will preserve the input order. This might help readability and debugging. It’s also nice if
you want to write the data back to a file. Prior to Python 3.6, however, this ordering was
not guaranteed, so you cannot rely upon it if compatibility with older versions of Python is
required. Order is also not guaranteed if multiple deletions and insertions have taken place.
To obtain the values stored in a dictionary, use the dict.values() method. To obtain
key-value pairs, use dict.items(). For example, here’s how to iterate over the entire
contents of a dictionary as key-value pairs:
for sym, price in prices.items():
print(f'{sym} = {price}')

1.12 Iteration and Looping


The most widely used looping construct is the for statement that iterates over a collection
of items. One common form of iteration is to loop over all the members of a
sequence —such as a string, list, or tuple. Here’s an example:
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
print(f'2 to the {n} power is {2**n}')

In this example, the variable n will be assigned successive items from the list [1, 2, 3,
4, ..., 9] on each iteration. Since looping over ranges of integers is quite common,
there is a shortcut:
for n in range(1, 10):
print(f'2 to the {n} power is {2**n}')

The range(i, j [,step]) function creates an object that represents a range of integers
with values from i up to, but not including, j. If the starting value is omitted, it’s taken to
be zero. An optional stride can also be given as a third argument. Here are some examples:
a = range(5) # a = 0, 1, 2, 3, 4
b = range(1, 8) # b = 1, 2, 3, 4, 5, 6, 7
c = range(0, 14, 3) # c = 0, 3, 6, 9, 12
d = range(8, 1, -1) # d = 8, 7, 6, 5, 4, 3, 2
22 Chapter 1 Python Basics

The object created by range() computes the values it represents on demand when
lookups are requested. Thus, it’s efficient to use even with a large range of numbers.
The for statement is not limited to sequences of integers. It can be used to iterate over
many kinds of objects including strings, lists, dictionaries, and files. Here’s an example:
message = 'Hello World'
# Print out the individual characters in message
for c in message:
print(c)

names = ['Dave', 'Mark', 'Ann', 'Phil']


# Print out the members of a list
for name in names:
print(name)

prices = { 'GOOG' : 490.10, 'IBM' : 91.50, 'AAPL' : 123.15 }


# Print out all of the members of a dictionary
for key in prices:
print(key, '=', prices[key])

# Print all of the lines in a file


with open('foo.txt') as file:
for line in file:
print(line, end='')

The for loop is one of Python’s most powerful language features because you can create
custom iterator objects and generator functions that supply it with sequences of values.
More details about iterators and generators can be found later in Chapter 6.

1.13 Functions
Use the def statement to define a function:
def remainder(a, b):
q = a // b # // is truncating division.
r = a - q * b
return r

To invoke a function, use its name followed by its arguments in parentheses, for
example result = remainder(37, 15).
It is common practice for a function to include a documentation string as the first
statement. This string feeds the help() command and may be used by IDEs and other
development tools to assist the programmer. For example:
def remainder(a, b):
'''
1.13 Functions 23

Computes the remainder of dividing a by b


'''
q = a // b
r = a - q * b
return r

If the inputs and outputs of a function aren’t clear from their names, they might be
annotated with types:
def remainder(a: int, b: int) -> int:
'''
Computes the remainder of dividing a by b
'''
q = a // b
r = a - q * b
return r

Such annotations are merely informational and are not actually enforced at runtime.
Someone could still call the above function with non-integer values, such as result =
remainder(37.5, 3.2).
Use a tuple to return multiple values from a function:
def divide(a, b):
q = a // b # If a and b are integers, q is integer
r = a - q * b
return (q, r)

When multiple values are returned in a tuple, they can be unpacked into separate
variables like this:
quotient, remainder = divide(1456, 33)

To assign a default value to a function parameter, use assignment:


def connect(hostname, port, timeout=300):
# Function body
...

When default values are given in a function definition, they can be omitted from
subsequent function calls. An omitted argument will take on the supplied default value.
Here’s an example:
connect('www.python.org', 80)
connect('www.python.org', 80, 500)

Default arguments are often used for optional features. If there are many such
arguments, readability can suffer. It’s therefore recommended to specify such arguments
using keyword arguments. For example:
24 Chapter 1 Python Basics

connect('www.python.org', 80, timeout=500)

If you know the names of the arguments, all of them can be named when calling a
function. When named, the order in which they are listed doesn’t matter. For example,
this is fine:
connect(port=80, hostname='www.python.org')

When variables are created or assigned inside a function, their scope is local. That is,
the variable is only defined inside the body of the function and is destroyed when the
function returns. Functions can also access variables defined outside of a function as long as
they are defined in the same file. For example:
debug = True # Global variable

def read_data(filename):
if debug:
print('Reading', filename)
...

Scoping rules are described in more detail in Chapter 5.

1.14 Exceptions
If an error occurs in your program, an exception is raised and a traceback message appears:
Traceback (most recent call last):
File "readport.py", line 9, in <module>
shares = int(row[1])
ValueError: invalid literal for int() with base 10: 'N/A'

The traceback message indicates the type of error that occurred, along with its location.
Normally, errors cause a program to terminate. However, you can catch and handle
exceptions using try and except statements, like this:
portfolio = []
with open('portfolio.csv') as file:
for line in file:
row = line.split(',')
try:
name = row[0]
shares = int(row[1])
price = float(row[2])
holding = (name, shares, price)
portfolio.append(holding)
except ValueError as err:
1.14 Exceptions 25

print('Bad row:', row)


print('Reason:', err)

In this code, if a ValueError occurs, details concerning the cause of the error are placed
in err and control passes to the code in the except block. If some other kind of exception
is raised, the program crashes as usual. If no errors occur, the code in the except block is
ignored. When an exception is handled, program execution resumes with the statement
that immediately follows the last except block. The program does not return to the
location where the exception occurred.
The raise statement is used to signal an exception. You need to give the name of an
exception. For instance, here’s how to raise RuntimeError, a built-in exception:
raise RuntimeError('Computer says no')

Proper management of system resources such as locks, files, and network connections is
often tricky when combined with exception handling. Sometimes there are actions that
must be performed no matter what happens. For this, use try-finally. Here is an
example involving a lock that must be released to avoid deadlock:
import threading
lock = threading.Lock()
...
lock.acquire()
# If a lock has been acquired, it MUST be released
try:
...
statements
...
finally:
lock.release() # Always runs

To simplify such programming, most objects that involve resource management also
support the with statement. Here is a modified version of the above code:

with lock:
...
statements
...

In this example, the lock object is automatically acquired when the with statement
executes. When execution leaves the context of the with block, the lock is automatically
released. This is done regardless of what happens inside the with block. For example, if an
exception occurs, the lock is released when control leaves the context of the block.
The with statement is normally only compatible with objects related to system
resources or the execution environment— such as files, connections, and locks. However,
user-defined objects can have their own custom processing, as described further in
Chapter 3.
26 Chapter 1 Python Basics

1.15 Program Termination


A program terminates when no more statements exist to execute in the input program or
when an uncaught SystemExit exception is raised. If you want to force a program to quit,
here’s how to do it:
raise SystemExit() # Exit with no error message
raise SystemExit("Something is wrong") # Exit with error

On exit, the interpreter makes a best effort to garbage-collect all active objects.
However, if you need to perform a specific cleanup action (remove files, close a
connection), you can register it with the atexit module as follows:
import atexit

# Example
connection = open_connection("deaddot.com")

def cleanup():
print "Going away..."
close_connection(connection)

atexit.register(cleanup)

1.16 Objects and Classes


All values used in a program are objects. An object consists of internal data and methods
that perform various kinds of operations involving that data. You have already used objects
and methods when working with the built-in types such as strings and lists. For example:
items = [37, 42] # Create a list object
items.append(73) # Call the append() method

The dir() function lists the methods available on an object. It is a useful tool for
interactive experimentation when no fancy IDE is available. For example:
>>> items = [37, 42]
>>> dir(items)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
...
'append', 'count', 'extend', 'index', 'insert', 'pop',
'remove', 'reverse', 'sort']
>>>

When inspecting objects, you will see familiar methods such as append() and insert()
listed. However, you will also see special methods whose names begin and end with a
1.16 Objects and Classes 27

double underscore. These methods implement various operators. For example, the
__add__() method is used to implement the + operator. These methods are explained in
more detail in later chapters.
>>> items.__add__([73, 101])
[37, 42, 73, 101]
>>>

The class statement is used to define new types of objects and for object-oriented
programming. For example, the following class defines a stack with push() and pop()
operations:
class Stack:
def __init__(self): # Initialize the stack
self._items = [ ]

def push(self, item):


self._items.append(item)

def pop(self):
return self._items.pop()

def __repr__(self):
return f'<{type(self).__name__} at 0x{id(self):x}, size={len(self)}>'

def __len__(self):
return len(self._items)

Inside the class definition, methods are defined using the def statement. The first
argument in each method always refers to the object itself. By convention, self is the
name used for this argument. All operations involving the attributes of an object must
explicitly refer to the self variable.
Methods with leading and trailing double underscores are special methods. For
example, __init__ is used to initialize an object. In this case, __init__ creates an internal
list for storing the stack data.
To use a class, write code such as this:
s = Stack() # Create a stack
s.push('Dave') # Push some things onto it
s.push(42)
s.push([3, 4, 5])
x = s.pop() # x gets [3,4,5]
y = s.pop() # y gets 42

Within the class, you will notice that the methods use an internal _items variable.
Python does not have any mechanism for hiding or protecting data. However, there is a
programming convention wherein names preceded by a single underscore are taken to be
28 Chapter 1 Python Basics

“private.” In this example, _items should be treated (by you) as internal implementation
and not used outside the Stack class itself. Be aware that there is no actual enforcement of
this convention —if you want to access _items, you can do so at any time. You’ll just have
to answer to your coworkers when they review your code.
The __repr__() and __len__() methods are there to make the object play nicely with
the rest of the environment. Here, __len__() makes a Stack work with the built-in len()
function and __repr__() changes the way that a Stack is displayed and printed. It’s a good
idea to always define __repr__() as it can simplify debugging.
>>> s = Stack()
>>> s.push('Dave')
>>> s.push(42)
>>> len(s)
2
>>> s
<Stack at 0x10108c1d0, size=2>
>>>

A major feature of objects is that you can add to or redefine the capabilities of existing
classes via inheritance.
Suppose you wanted to add a method to swap the top two items on the stack. You
might write a class like this:
class MyStack(Stack):
def swap(self):
a = self.pop()
b = self.pop()
self.push(a)
self.push(b)

MyStack is identical to Stack except that it has a new method, swap().


>>> s = MyStack()
>>> s.push('Dave')
>>> s.push(42)
>>> s.swap()
>>> s.pop()
'Dave'
>>> s.pop()
42
>>>

Inheritance can also be used to change the behavior of an existing method. Suppose
you want to restrict the stack to only hold numeric data. Write a class like this:
class NumericStack(Stack):
def push(self, item):
1.16 Objects and Classes 29

if not isinstance(item, (int, float)):


raise TypeError('Expected an int or float')
super().push(item)

In this example, the push() method has been redefined to add extra checking. The
super() operation is a way to invoke the prior definition of push(). Here’s how this class
would work:
>>> s = NumericStack()
>>> s.push(42)
>>> s.push('Dave')
Traceback (most recent call last):
...
TypeError: Expected an int or float
>>>

Often, inheritance is not the best solution. Suppose you wanted to define a simple
stack-based 4-function calculator that worked like this:
>>> # Calculate 2 + 3 * 4
>>> calc = Calculator()
>>> calc.push(2)
>>> calc.push(3)
>>> calc.push(4)
>>> calc.mul()
>>> calc.add()
>>> calc.pop()
14
>>>

You might look at this code, see the use of push() and pop(), and think that
Calculator could be defined by inheriting from Stack. Although that would work, it is
probably better to define Calculator as a completely separate class:
class Calculator:
def __init__(self):
self._stack = Stack()

def push(self, item):


self._stack.push(item)

def pop(self):
return self._stack.pop()

def add(self):
self.push(self.pop() + self.pop())
30 Chapter 1 Python Basics

def mul(self):
self.push(self.pop() * self.pop())

def sub(self):
right = self.pop()
self.push(self.pop() - right)

def div(self):
right = self.pop()
self.push(self.pop() / right)

In this implementation, a Calculator contains a Stack as an internal implementation


detail. This is an example of composition. The push() and pop() methods delegate to the
internal Stack. The main reason for taking this approach is that you don’t really think of
the Calculator as a Stack. It’s a separate concept — a different kind of object. By analogy,
your phone contains a central processing unit (CPU) but you don’t usually think of your
phone as a type of CPU.

1.17 Modules
As your programs grow in size, you will want to break them into multiple files for easier
maintenance. To do this, use the import statement. To create a module, put the relevant
statements and definitions into a file with a .py suffix and the same name as the module.
Here’s an example:
# readport.py
#
# Reads a file of 'NAME,SHARES,PRICE' data

def read_portfolio(filename):
portfolio = []
with open(filename) as file:
for line in file:
row = line.split(',')
try:
name = row[0]
shares = int(row[1])
price = float(row[2])
holding = (name, shares, price)
portfolio.append(holding)
except ValueError as err:
print('Bad row:', row)
print('Reason:', err)
return portfolio
Another Random Scribd Document
with Unrelated Content
CHAPTER IV

SUBMARINES IN THE CIVIL WAR

T
he most powerful battleship in the world, half a century ago,
was the U.S.S. New Ironsides. She was a wooden-hulled,
ship-rigged steamer of 3486 tons displacement—about one
tenth the size of a modern superdreadnought—her sides plated with
four inches of iron armor, and carrying twenty heavy guns. On the
night of October 5, 1863, the New Ironsides was on blockade duty
off Charleston Harbor, when Ensign Howard, the officer of the deck,
saw something approaching that looked like a floating plank. He
hailed it, and was answered by a rifle ball that stretched him,
mortally wounded, on the deck. An instant later came the flash and
roar of a tremendous explosion, a column of water shot high into the
air alongside, and the New Ironsides was shaken violently from stem
to stern.

The Confederate submarine David had crept up and driven a


spar-torpedo against Goliath’s armor.
But except for a few splintered timbers, a flooded engine-room,
and a marine’s broken leg, no damage had been done. As the
Confederate craft was too close and too low in the water for the
broadside guns to bear, the crew of the ironclad lined the rail and
poured volley after volley of musketry into their dimly seen
adversary till she drifted away into the night. Her crew of seven men
had dived overboard at the moment of impact, and were all picked
up by different vessels of the blockading fleet, except the engineer
and one other, who swam back to the David, started her engine
again, and brought her safely home to Charleston.

Views of a Confederate David.


From Scharf’s History of the Confederate States Navy.

The David was a cigar-shaped steam launch, fifty-four feet long


and six feet broad at the thickest point. Projecting from her bow was
a fifteen-foot spar, with a torpedo charged with sixty pounds of
gunpowder at the end of it. This was exploded by the heat given off
by certain chemicals, after they were shaken up together by the
impact of the torpedo against the enemy’s ship. The David, steaming
at her full speed of seven knots an hour, struck squarely against the
New Ironsides at the water-line and rebounded to a distance of
seven or eight feet before this clumsy detonator could do its work.
When the explosion came, the intervening body of water prevented
it from doing any great damage.
The David was not a true submarine but a surface torpedo boat,
that could be submerged till only the funnel and a small pilot-house
were exposed. A number of other Davids were built and operated by
the Confederate States navy, but the first of them was the only one
to accomplish anything.

C. S. S. Hundley.
The Only Submarine to sink a Hostile Warship before the Outbreak of
the Present War.

The one real submarine possessed by the Confederacy was not a


David, though she is usually so called. This was the C.S.S. Hundley,
a hand-power “diving-boat” not unlike Fulton’s Nautilus, but very
much clumsier and harder to manage. She had ballast tanks and a
pair of diving-planes for steering her up and down, and she was
designed to attack an enemy’s ship by swimming under it, towing a
torpedo that would explode on striking her opponent’s keel.
The Hundley was built at Mobile, Alabama, by the firm of
Hundley and McKlintock, named for the senior partner, and brought
to Charleston on a flatcar. There she was manned by a crew of nine
volunteers, eight of whom sat in a row and turned the cranks on the
propellor-shaft, while the ninth man steered. There was no conning-
tower and the forward hatchway had to be left open for the
helmsman to look out of while running on the surface. On the
Hundley’s first practice cruise, the wash from the paddle-wheels of a
passing steamer poured suddenly down the open hatchway. Only the
steersman and commanding officer, Lieutenant Payne, had time to
save himself before the submarine sank, drowning the rest of her
crew.
The boat was raised and Payne took her out with a new crew.
This time a sudden squall sank her before they could close the
hatches, and Payne escaped, with two of his men. He tried a third
time, only to be capsized off Fort Sumter, with the loss of four of his
crew. On the fourth trip, the hatches were closed, the tanks filled,
and an attempt was made to navigate beneath the surface. But the
Hundley dived too suddenly, stuck her nose deep into the muddy
bottom, and stayed there till her entire crew were suffocated. On the
fifth trial she became entangled in the cable of an anchored vessel,
with the same result.
By this time the submarine’s victims numbered thirty-five, and
the Confederates had nicknamed her the “Peripatetic Coffin.” But at
the sixth call for volunteers, they still came forward. It was decided
to risk no more lives on practice trips but to attack at once. In spite
of the protests of Mr. Hundley, the designer of the craft, her latest
and last commander, Lieutenant Dixon of the 21st South Carolina
Infantry, was ordered by General Beauregard to use the vessel as a
surface torpedo-boat, submerged to the hatch-coaming and with the
hatches open. A spar-torpedo, to be exploded by pulling a trigger
with a light line running back into the boat, was mounted on the
bow. Thus armed, and manned by Lieutenant Dixon, Captain
Carlson, and five enlisted men of their regiment, the little Hundley
put out over Charleston bar on the night of February 17, 1864, to
attack some vessel of the blockading fleet. This proved to be the
U.S.S. Housatonic, a fine new thirteen-gun corvette of 1264 tons.
What followed is best described by Admiral David Porter in his “Naval
History of the Civil War.”
“At about 8.45 P.M., the officer of the deck on board the
unfortunate vessel discovered something about 100 yards away,
moving along the water. It came directly towards the ship, and
within two minutes of the time it was first sighted was alongside.
The cable was slipped, the engines backed, and all hands called to
quarters. But it was too late—the torpedo struck the Housatonic just
forward of the mainmast, on the starboard side, on a line with the
magazine. The man who steered her (the Hundley) knew where the
vital spots of the steamer were and he did his work well. When the
explosion took place the ship trembled all over as if by the shock of
an earthquake, and seemed to be lifted out of the water, and then
sank stern-foremost, heeling to port as she went down.”
The Hundley was not seen after the explosion, and it was
supposed that she had backed away and escaped. But when peace
came, and Charleston Harbor was being cleared of the wrecks with
which war had clogged it, the divers sent down to inspect the
Housatonic found the Hundley lying beside her. Sucked in by the
rush of the water through the hole her torpedo had made, she had
been caught and dragged down by her own victim. All the Hundley’s
crew were found dead within her. So perished the first and last
submarine to sink a hostile warship, before the outbreak of the
present war. A smaller underwater boat of the same type was
privately built at New Orleans at the beginning of the war, lost on
her trial trip, and not brought up again till after peace was declared.
The North had a hand-power submarine, that was built at the
Georgetown Navy Yard in 1862. It was designed by a Frenchman,
whose name is now forgotten but who might have been a
contemporary of Cornelius Van Drebel. Except that its hull was of
steel instead of wood and greased leather, this first submarine of the
United States navy was no better than an eel-boat of the
seventeenth century. It was propelled by eight pairs of oars, with
hinged blades that folded up like a book on the return stroke. The
boat was thirty-five feet long and six in diameter, and was rowed by
sixteen men. It was submerged by flooding ballast tanks. There was
an oxygen tank and an apparatus for purifying the used air by
blowing it over lime. A spar-torpedo was to be run out on rollers in
the bow.
Ten thousand dollars was paid to the inventor of this medieval
leftover, and he prudently left the country before he could be called
on to operate it, though he had been promised a reward of five
thousand dollars for every Confederate ironclad he succeeded in
blowing up. Like the first Monitor, this nameless submarine was lost
in a storm off Cape Hatteras, while being towed by a steamer.
After the loss of the Housatonic, the North built two semi-
submersible steam torpedo-boats on the same idea as the David,
but larger and faster. Both were armed with spar-torpedoes and
fitted with ballast tanks to sink them very low in the water when
they attacked. The smaller of the two, the Stromboli, could be
submerged till only her pilot-house, smoke-stack, and one ventilator
showed above the water. The other boat was called the Spuyten
Duyvil. She could be sunk till her deck, which was covered with
three inches of iron armor, was level with the water, but she bristled
with masts, funnels, conning-towers, ventilators, and other
excrescences that sprouted out of her hull at the most unexpected
places. Neither of these craft was ever used in action.
CHAPTER V

THE WHITEHEAD TORPEDO

H
ow best to float a charge of explosives against the hull of an
enemy’s ship and there explode it is the great problem of
torpedo warfare. The spar-torpedo, that did such effective
work in the Civil War, was little more than a can of gunpowder on the
end of a stick. This stick or spar was mounted usually on the bow of a
steam-launch, either partially submerged, like the David, or boldly
running on the surface over log-booms and through a hail of bullets
and grapeshot, as when Lieutenant Cushing sank the Confederate
ironclad Albemarle. Once alongside, the spar-torpedo was run out to its
full length, raised, depressed, and finally fired by pulling different
ropes. So small was the chance of success and so great the danger to
the launch’s crew that naval officers and inventors all the world over
sought constantly for some surer and safer way.

Early in the sixties, an Austrian artillery officer attached to the coast


defenses conceived the idea of sending out the launch without a crew.
He made some drawings of a big toy boat, to be driven by steam or hot
air or even by clockwork, and steered from the shore by long ropes. As
it would have no crew, this boat could carry the explosives in its hull,
and the spars which were to project from it in all directions would carry
no torpedoes themselves but would serve to explode the boat’s cargo
of guncotton by firing a pistol into it, as soon as one of the spars came
into contact with the target. Before he could carry out his ideas any
further, this officer died and his plans were turned over to Captain
Lupuis of the Austrian navy. Lupuis experimented diligently with surface
torpedoes till 1864, but found that he would have to discover some
better steering-device than ropes from the shore and some other
motive-power than steam or clockwork. So he consulted with Mr.
Whitehead, the English manager of a firm of engine manufacturers at
the seaport of Fiume.
Whitehead gave the torpedo a fish-shaped hull, so that it could run
beneath instead of on the surface. For motive-power he used
compressed air, which proved much superior to either steam or
clockwork. And by improving its rudders, he enabled the little craft to
keep its course without the aid of guide-ropes from the shore. The
chief defect of the first Whitehead torpedoes, which were finished and
tried in 1866, was that they kept bobbing to the surface, or else they
would dive too deep and pass harmlessly under the target. To correct
this defect, Whitehead invented by 1868 what he called the “balance
chamber.” Then, as now, each torpedo was divided into a number of
separate compartments or chambers, and in one of these the inventor
placed a most ingenious device for keeping the torpedo at a uniform
depth. The contents of the balance-chamber was Whitehead’s great
secret, and it was not revealed to the public for twenty years.
The automobile or, as it was then called, the “submarine
locomotive” torpedo was now a practicable, though by no means
perfected, weapon, and the Austrian naval authorities gave it a
thorough trial at Fiume in 1868. Whitehead rigged up a crude ejecting
tube on the bow of a gunboat, and successfully discharged two of his
torpedoes at a yacht. The Austrian government promptly adopted the
weapon, but could not obtain a monopoly of it, for Whitehead was a
patriotic Englishman. The British admiralty invited him to England two
years later, and after careful trials of its own, induced the English
government to buy Whitehead’s secret and manufacturing rights for
$45,000. Other nations soon added “Whiteheads” to their navies, and
in 1873 there was built in Norway a large, fast steam launch for the
express purpose of carrying torpedoes and discharging them at an
enemy. Every one began to build larger and swifter launches, till they
evolved the torpedo-boat and the destroyer of to-day.
The torpedo itself has undergone a similar development in size and
efficiency. The difference between the Whiteheads of forty-five years
ago and those of to-day is strikingly shown in the following table:
British Naval Torpedoes of 1870
Length, Diameter, Charge, Range, Speed,
Feet Inches Pounds Yards Knots
Large 14 16 67 600 7.5
guncotton
Small 13 10.58 14 18 200 8.5
in. dynamite

British Naval Torpedoes of 1915


Large 21 21 330 12,000 48
guncotton
Small 18 18 200 16,000 36
guncotton

The length of a large modern torpedo, it will be observed, is only


three inches less than that of Fulton’s famous submarine boat of 1801.
A Whitehead torpedo is really a small automatic submarine, steered
and controlled by the most ingenious and sensitive machinery, as surely
as if it were manned by a crew of Lilliputian seamen.
Projecting from the head is the “striker,” a rod which, when the
torpedo runs into anything hard, is driven back in against a detonator
or “percussion-cap” of fulminate of mercury. Just as the hammer of a
toy “cap-pistol” explodes a paper cap, so the sudden shock of the in-
driven striker explodes the fulminate, which is instantly expanded to
more than two thousand times its former size. This, in turn, gives a
severe blow to the surrounding “primer” of dry guncotton. The primer
is exploded, and by its own expansion sets off the main charge of
several hundred pounds of wet guncotton.
The reason for this is that though wet guncotton is safe to handle
because a very great shock is required to make it explode, dry
guncotton is much less so, while a shell or torpedo filled with fulminate
of mercury would be more dangerous to its owners than to their
enemies, because the slightest jar might set it off prematurely. Every
precaution is taken to prevent a torpedo’s exploding too soon and
damaging the vessel from which it is fired.
When the torpedo is shot out of the tube, by compressed air, like a
pea from a pea-shooter, the striker is held fast by the “jammer”: a
small propellor-shaped collar, whose blades begin to revolve as soon as
they strike the water, till the collar has unscrewed itself and dropped off
after the torpedo has traveled about forty feet. A copper pin that runs
through the striker-rod is not removed but must be broken short off by
a blow of considerable violence, such as would be given by running into
a ship’s hull. As a third safeguard, there is a strong safety-catch, that
must be released by hand, just before the torpedo is placed in the
tube.
The explosive charge of two or three hundred pounds of wet
guncotton is called the “war-head.” In peace and for target-practice it is
replaced by a dummy head of thick steel. The usual target is the space
between two buoys moored a ship’s length or less apart. At the end of
a practice run, the torpedo rises to the surface, where it can be
recovered and used again. This is distinctly worth while, for a modern
torpedo costs more than seven thousand dollars.
Back of the war-head is the air-chamber, that contains the motive-
power of this miniature submarine. The air is either packed into it by
powerful pumps, on shore or shipboard, or else drawn from one of the
storage flasks of compressed air, a number of which are carried on
every submarine. The air-chamber of a modern torpedo is charged at a
pressure of from 2000 to 2500 pounds per square inch. As the torpedo
leaves the tube, a lever on its back is struck and knocked over by a
little projecting piece of metal, and the starting-valve of the air-
chamber is opened. But if the compressed air were allowed to reach
and start the engines at once, they would begin to revolve the
propellors while they were still in the air inside the tube. This would
cause the screws to “race,” or spin round too rapidly and perhaps break
off. So there is a “delaying-valve,” which keeps the air away from the
engines till another valve-lever is swung over by the impact of the
water against a little metal flap.
As the compressed air rushes through the pipe from the chamber
to the engine-room, it passes through a “reducing-valve,” which keeps
it from spurting at the start and lagging at the finish. By supplying the
air to the engines at a reduced but uniform pressure, this device
enables the torpedo to maintain the same speed throughout the run. At
the same time the compressed air is heated by a small jet of burning
oil, with a consequent increase in pressure, power, and speed,
estimated at 30 per cent. All these devices are kept not in the air-
chamber itself but in the next compartment, the balance-chamber.
Here is the famous little machine, once a close-kept secret but now
known to all the world, that holds the torpedo at any desired depth.
Think of a push-button, working in a tube open to the sea, with the
water pressure pushing the button in and a spiral spring inside shoving
it out. This push-button—called a “hydrostatic valve”—is connected by
a system of levers with the two diving-planes or horizontal rudders that
steer the torpedo up or down. By turning a screw, the spring can be
adjusted to exert a force equal to the pressure of the water at any
given depth. If the torpedo dives too deep, the increased water-
pressure forces in the valve, moves the levers, raises the diving-planes,
and steers the torpedo towards the surface. As the water pressure
grows less, the spring forces out the valve, depresses the diving-
planes, and brings the miniature submarine down to its proper depth
again. When his torpedoes grew too big to be controlled by the
comparatively feeble force exerted by the hydrostatic valve, Whitehead
invented the “servo-motor”: an auxiliary, compressed-air engine, less
than five inches long, sensitive enough to respond to the slightest
movement of the valve levers but strong enough to steer the largest
torpedo, exactly as the steam steering-gear moves the huge rudder of
an ocean liner.
There is also a heavy pendulum, swinging fore and aft and
attached to the diving-planes, that checks any sudden up-or-down
movement of the torpedo by inclining the planes and restoring the
horizontal position.
Next comes the engine-room, with its three-cylinder motor, capable
of developing from thirty-five to fifty-five horse-power. The exhaust air
from the engine passes out through the stern in a constant stream of
bubbles, leaving a broad white streak on the surface of the water as
the torpedo speeds to its mark.
The aftermost compartment is called the buoyancy chamber.
Besides adding to the floatability of the torpedo, this space also holds
the engine shaft and the gear attaching it to the twin propellors. The
first Whiteheads were single-screw boats. But the revolution of the
propellor in one direction set up a reaction that caused the torpedo
itself to partially revolve or heel over in the other, disturbing its rudders
and swerving it from its course. This reaction is neutralized by using
two propellers, one revolving to the right, the other to the left. Instead
of being placed side by side, as on a steamer, they are mounted one
behind the other, with the shaft of one revolving inside the hollow shaft
of the other, and in the opposite direction.
Long after they could be depended on to keep a proper depth, the
Whiteheads and other self-propelled torpedoes were liable to swing
suddenly to port or starboard, or even turn completely round. During
the war between Chile and Peru, in 1879, the Peruvian ironclad Huascar
discharged an automobile torpedo that went halfway to the target,
changed its mind, and was coming back to blow up its owners when an
officer swam out to meet it and succeeded in turning it aside, for the
torpedoes of that time were slow and small as well as erratic.
Nowadays a torpedo is kept on a straight course by a gyroscope
placed in the buoyancy chamber. Nearly every boy knows the
gyroscopic top, like a little flywheel, that you can spin on the edge of a
tumbler. The upper part of this toy is a heavy little metal wheel, and if
you try to push it over while it is spinning, it resists and pushes back,
as if it were alive. A similar wheel, weighing about two pounds, is
placed in the buoyancy chamber of a Whitehead. When the torpedo
starts, it releases either a powerful spring or an auxiliary compressed
air engine that sets the gyroscope to spinning at more than two
thousand revolutions a minute. It revolves vertically, in the fore-and-aft
line of the torpedo, and is mounted on a pivoted stand. If the torpedo
deviates from its straight course, the gyroscope does not, and the
consequent change in their relative positions brings the flywheel into
contact with a lever running to the servo-motor that controls the two
vertical rudders, which soon set the torpedo right again.
Cross-section of a Whitehead Torpedo.
Redrawn from the Illustrated London News.
A, Striker which, when driven in, fires the charge; B, Safety pin, which is
removed just before the torpedo is discharged; C, Detonating charge; D,
Explosive-head, or war-head; filled with guncotton; E, Primer charge of dry
guncotton in cylinder; F, Balance chamber; G, Starting pin; H, Buoyancy
chamber; I, Propellor shaft; J, Vertical rudder; K, Twin screws; L, Horizontal
rudder; M, Gyroscope controlling torpedo’s course; N, Engines propelling
machinery; O, Pendulum acting on the horizontal rudder which controls the
depth of submergence; P, Hydrostatic valve; Q, Air-chamber, filled with
compressed air; provides motive-power for the engines; R, “Jammer” or
release propellor.

Thus guided and driven, a modern torpedo speeds swiftly and


surely to its target, there to blow itself into a thousand pieces, with a
force sufficient to sink a ship a thousand times its size.
The Whitehead is used by every navy in the world except the
German, which has its own torpedo: the “Schwartzkopf.” This, however,
is practically identical with the Whitehead, except that its hull is made
of bronze instead of steel and its war-head is charged with
trinitrotuluol, or T.N.T., a much more powerful explosive than
guncotton.
After the Russo-Japanese War, when several Russian battleships
kept afloat although they had been struck by Japanese torpedoes,
many naval experts declared that an exploding war-head spent most of
its energy in throwing a great column of water up into the air, instead
of blowing in the side of the ship. So Commander Davis of the United
States navy invented his “gun-torpedo.” This is like a Whitehead in
every respect except that instead of a charge of guncotton it carries in
its head a short eight-inch cannon loaded with an armor-piercing shell
and a small charge of powder. In this type of torpedo, the impact of the
striker against the target serves to fire the gun. The shell then passes
easily through the thin side of the ship below the armor-belt and
through any protecting coal-bunkers and bulkheads it may encounter,
till it reaches the ship’s vitals, where it is exploded by the delayed
action of an adjustable time-fuse. What would happen if it burst in a
magazine or boiler-room is best left to the imagination. Several Davis
gun-torpedoes have been built and used against targets with very
satisfactory results, but they have not yet been used in actual warfare.
Courtesy of the Electric Boat Company.
Davis Gun-Torpedo after discharge, showing eight-inch gun
forward of air-flask.

Mr. Edward F. Chandler, M.E., one of the foremost torpedo-experts


in America, is dissatisfied with the compressed-air driven gyroscope,
both because it does not begin to revolve till after the torpedo has been
launched and perhaps deflected from its true course, and because it
cannot be made to spin continuously throughout the long run of a
modern torpedo. He proposes to remove the compressed-air servo-
motors, both for this purpose and for controlling the horizontal rudders
by the hydrostatic valve, and replace them with an electrical-driven
gyroscope and depth-gear. The increased efficiency of the latter would
enable him to get rid of the heavy, uncertain pendulum, thus allowing
for the weight of the storage batteries. Mr. Chandler declares that his
electrically-controlled torpedo can be lowered over the side of a small
boat, headed in any desired direction, and started, without any
9
launching-tube.
Courtesy of the Electric Boat Company.
Effect of Davis Gun-Torpedo on a specially-constructed
target.

Though the automobile torpedo has been brought to so high a


state of perfection, the original idea of steering from the shore has not
been abandoned. The Brennan and Sims-Edison controllable torpedoes
were driven and steered by electricity, receiving the current through
wires trailed astern and carrying little masts and flags above the
surface to guide the operator on shore. But these also served as a
warning to the enemy and gave him too good a chance either to avoid
the torpedo or destroy it with machine-gun fire. Then, too, the trailing
wires reduced its speed and were always liable to get tangled in the
propellors. Controllable torpedoes of this type were abandoned before
the outbreak of the present war and will probably never be used in
action.
A new and more promising sort of controllable torpedo was
immediately suggested by the invention of wireless telegraphy. Many
inventors have been working to perfect such a weapon, and a young
American engineer, Mr. John Hays Hammond, Jr., seems to have
succeeded. From his wireless station on shore, Mr. Hammond can make
a small, crewless electric launch run hither and yon as he pleases about
the harbor of Gloucester, Massachusetts. The commander and many of
the officers of the United States coast artillery corps have carefully
inspected and tested this craft, which promises to be the forerunner of
a new and most formidable species of coast defense torpedo.
CHAPTER VI

FREAKS AND FAILURES

D
uring the half-century following the death of Fulton, scarcely
a year went by without the designing or launching of a new
man-power submarine. Some of these boats, notably those
of the Bavarian Wilhelm Bauer, were surprisingly good, others were
most amazingly bad, but none of them led to anything better.
Inventor after inventor wasted his substance discovering what Van
Drebel, Bushnell, and Fulton had known before him, only to die and
have the same facts painfully rediscovered by some one on the other
side of the earth.

A striking example of this lack of progress is Halstead’s


Intelligent Whale. Built for the United States navy at New York, in
the winter of 1864–5, this craft is no more modern and much less
efficient than Fulton’s Nautilus of 1801. The Intelligent Whale is a
fat, cigar-shaped, iron vessel propelled by a screw cranked by
manpower and submerged by dropping two heavy anchors to the
bottom and then warping the boat down to any desired depth. A
diver can then emerge from a door in the submarine’s bottom, to
place a mine under a hostile ship. It was not until 1872 that the
Intelligent Whale was sent on a trial trip in Newark Bay. Manned by
an utterly inexperienced and very nervous crew, the clumsy
submarine got entirely out of control and had to be hauled up by a
cable that had been thoughtfully attached to her before she went
down. Fortunately no lives had been lost, but the wildest stories
were told and printed, till the imaginary death-roll ran up to forty-
nine. The Intelligent Whale was hauled up on dry land and can still
be seen on exhibition at the corner of Third Street and Perry Avenue
in the Brooklyn Navy Yard.
Lack of motive-power was the reason why man-sized submarines
lagged behind their little automatic brethren, the Whitehead
torpedoes. Compressed air was just the thing for a spurt, but when
two Frenchmen, Captain Bourgois and M. Brun, built the Plongeur, a
steel submarine 146 feet long and 12 feet in diameter, at Rochefort
in 1863, and fitted it with an eighty-horse-power, compressed-air
engine, they discovered that the storage-flasks emptied themselves
too quickly to permit a voyage of any length.
The Plongeur also proved that while you can sink a boat to the
bottom by filling her ballast-tanks or make her rise to the surface by
emptying them, you cannot make her float suspended between two
bodies of water except by holding her there by some mechanical
means. Without anything of the kind, the Plongeur kept bouncing up
and down like a rubber ball. Once her inventors navigated her
horizontally for some distance, only to find that she had been sliding
on her stomach along the soft muddy bottom of a canal. Better
results were obtained after the Plongeur was fitted with a crude pair
of diving-planes. But the inefficiency of her compressed-air engine
caused her to be condemned and turned into a water tank.
The Intelligent Whale.
Drawn by Lieutenant F. M. Barber, U. S. N., in 1875.

Electricity was first applied in 1861 by another Frenchman,


named Olivier Riou. This is the ideal motive-power for underwater
boats, and it was at this time that Jules Verne described the ideal
submarine in his immortal story of “Twenty Thousand Leagues Under
the Sea.” But before we can have a Nautilus like Captain Nemo’s we
must discover an electric storage battery of unheard-of lightness and
capacity.

Le Plongeur.
There was a great revival of French interest in electric
submarines after Admiral Aube, who was a lifelong submarine “fan,”
became minister of marine in 1886. In spite of much ridicule and
opposition, he authorized the construction of a small experimental
vessel of this type called the Gymnote. She was a wild little thing
that did everything short of turning somersaults when she dived, but
she was enough of a success to be followed by a larger craft named,
after the great engineer who had designed her predecessor, the
Gustave Zédé.
“The history of the Gustave Zédé shows how much in earnest
the French were in the matter of submarines. When she was first
launched she was a failure in almost every respect, and it was only
after some years, during which many alterations and improvements
were carried out, that she became a serviceable craft. At first
nothing would induce the Gustave Zédé to quit the surface, and
when at last she did plunge she did it so effectually that she went
down to the bottom in 10 fathoms of water at an angle of 30
degrees. The committee of engineers were on board at the time,
and it speaks well for their patriotism that they did not as a result of
their unpleasant experience condemn the Gustave Zédé and advise
10
the government to spend no more money on submarine craft.”
Twenty-nine other electric submarines were built for the French
navy between 1886 and 1901. During the same period, a French
gentleman named M. Goubet built and experimented with two very
small electric submarines, each of which was manned by two men,
who sat back to back on a sort of settee stuffed with machinery.
Little or big, all these French boats had the same fatal defect: lack of
power. Their storage batteries, called on to propel them above, as
well as below, the surface, became exhausted after a few hours’
cruising. They were as useless for practical naval warfare as an
electric run-about would be to haul guns or carry supplies in
Flanders.
But if compressed-air and electricity were too quickly exhausted,
gasoline or petroleum was even less practicable for submarine
navigation. To set an oil-engine, that derives its power from the
explosion of a mixture of oil-vapor and air, at work in a small closed
space like the interior of a submarine, would soon make it
uninhabitable. While Mr. Holland was puzzling how to overcome this
difficulty, in the middle eighties, a Swedish inventor named
Nordenfeldt was building submarines to be run by steam-power.
Mr. Nordenfeldt, who is remembered to-day as the inventor of
the famous gun that bears his name, had taken up the idea of an
English clergyman named Garett, who in 1878 had built a submarine
called the Resurgam, or “I Shall Rise.” Garett’s second boat, built a
year later, had a steam-engine. When the vessel was submerged,
the smoke-stack was closed by a sliding panel, the furnace doors
were shut tight, and the engine run by the steam given off by a big
tank full of bottled-up hot water. Nordenfeldt improved this system
till his hot-water tanks gave off enough steam to propel his boat
beneath the surface for a distance of fourteen miles.
He also rediscovered and patented Bushnell’s device for
submerging a boat by pushing it straight down and holding it under
with a vertical propellor. His first submarine had two of these, placed
in sponsons or projections on either side of the center of the hull.
The Nordenfeldt boats, with their cigar-shaped hulls and projecting
smoke-stacks, looked like larger editions of the Civil War Davids, and
like them, could be submerged by taking in water-ballast till only a
strip of deck with the funnel and conning-tower projected above the
surface. Then the vertical propellors would begin to revolve and
force the boat straight down on an even keel. Mr. Nordenfeldt
insisted with great earnestness that this was the only safe and
proper way to submerge a submarine. If you tried to steer it
downward with any kind of driving-planes, he declared, then the
boat was liable to keep on descending, before you could pull its head
up, till it either struck the bottom or was crushed in by the pressure
of too great a depth of water. There was a great deal of truth in this,
but Mr. Nordenfeldt failed to realize that if one of his vertical
propellors pushed only a little harder than the other, then the keel of
his own submarine was going to be anything but even.
Steam Submarine Nordenfeldt II, at Constantinople, 1887.
Observe vertical-acting propellors on deck.
Reproduced from “Submarine Navigation, Past and Present” by Alan H.
Burgoyne, by permission of E. P. Dutton & Company.

The first Nordenfeldt boat was launched in 1886 and bought by


Greece, after a fairly successful trial in the Bay of Salamis. Two
larger and more powerful submarines: Nordenfeldt II and III, were
promptly ordered by Greece’s naval rival Turkey. Each of these was
125 feet long, or nearly twice the length of the Greek boat, and each
carried its two vertical propellors on deck, one forward and the other
aft. Both boats were shipped in sections to Constantinople in 1887,
but only Nordenfeldt II was put together and tried. She was one of
the first submarines to be armed with a bow torpedo-tube for
discharging Whiteheads, and as a surface torpedo-boat, she was a
distinct success. But when they tried to navigate her under water
there was a circus.
No sooner did one of the crew take two steps forward in the
engine-room than down went the bow. The hot water in the boilers
and the cold water in the ballast-tanks ran downhill, increasing the
slant still further. English engineers, Turkish sailors, monkey-
wrenches, hot ashes, Whitehead torpedoes, and other movables
came tumbling after, till the submarine was nearly standing on her
head, with everything inside packed into the bow like toys in the toe
of a Christmas stocking. The little vertical propellors pushed and
pulled and the crew clawed their way aft, till suddenly up came her
head, down went her tail, and everything went gurgling and
clattering down to the other end. Nordenfeldt II was a perpetual
see-saw, and no mortal power could keep her on an even keel. Once
they succeeded in steadying her long enough to fire a torpedo.
Where it went to, no man can tell, but the sudden lightening of the
bow and the recoil of the discharge made the submarine rear up and
sit down so hard that she began to sink stern-foremost. The water
was blown out of her ballast tanks by steam-pressure, and the main
engine started full speed ahead, till she shot up to the surface like a
flying-fish. The Turkish naval authorities, watching the trials from the
shores of the Golden Horn, were so impressed by these antics that
they bought the boat. But it was impossible to keep a crew on her,
for every native engineer or seaman who was sent on board
prudently deserted on the first dark night. So the Nordenfeldt II
rusted away till she fell to pieces, long before the Allied fleets began
the forcing of the Dardanelles.
Fantastic though their performances seem to us to-day, these
submarines represent the best work of some of the most capable
inventors and naval engineers of the nineteenth century. With them
deserve to be mentioned the boats of the Russian Drzewiecki and
the Spaniard Peral. Failures though they were, they taught the world
many valuable lessons about the laws controlling the actions of
submerged bodies.
Bauer’s Submarine Concert, Cronstadt Harbor, 1855. See
footnote, page 120
An original drawing by the author, Alan H. Burgoyne; reproduced from
“Submarine Navigation, Past and Present,” by permission of E. P.
Dutton & Company.

But many of the underwater craft invented between 1850 and


1900 can be classified only as freaks. Most of them, fortunately,
were designed but never built, and those that were launched
miraculously refrained from drowning any of their crews. There were
submarines armed with steam-driven gimlets: the
“nimble tail,
Made like an auger, with which tail she wriggles,
Betwixt the ribs of a ship and sinks it straight,”

that Ben Jonson playfully ascribed to Van Drebel. Dr. Lacomme, in


1869, proposed a submarine railroad from Calais to Dover, with
tracks laid on the bottom of the Channel and cars that could cast off
their wheels and rise to the surface in case of accident. Lieutenant
André Constantin designed, during the siege of Paris, a boat to be
submerged by drawing in pistons working in large cylinders open to
the water. A vessel was actually built on this principle in England in
1888, and submerged in Tilbury Docks, where the soft mud at the
bottom choked the cylinders so that the pistons could not be driven
out again and the boat was brought up with considerable difficulty.
Two particularly delirious inventors claimed that their submarines
could also be used as dirigible balloons. Boucher’s underwater boat
of 1886 was to have gills like a fish, so that it need never rise to the
surface for air, and was further adorned with spring-buffers on the
bottom, oars, a propellor under the center of the keel, and a
movable tail for sculling the vessel forward. There were submarines
with paddle-wheels, submarines with fins, and submarines with
wings. A Venezuelan dentist, Señor Lacavalerier, invented a double-
hulled, cigar-shaped boat, whose outer hull was threaded like a
screw, and by revolving round the fixed inner hull, bored its way
through the water. But he had been anticipated and outdone by
Apostoloff, a Russian, who not only designed a submarine on the
same principle but intended it to carry a large cabin suspended on
davits above the surface of the water, and declared that his vessel
would cross the Atlantic at an average speed of 111 knots an hour.
Apostoloff’s Proposed Submarine.
An original drawing by the author, Alan H. Burgoyne; reproduced from
“Submarine Navigation, Past and Present,” by permission of E. P.
Dutton & Company.

As late as 1898 the Spanish government, neglecting the


promising little electric boat built ten years before by Señor Peral,
was experimenting with two highly impossible submarines, one of
which was to be propelled by a huge clock-spring, while the other
was perfectly round. Needless to say, neither the sphere nor the toy
boat ever encountered the American fleet.
At the same time, the United States government declined to
accept the war services of the already practicable boats of the two
American inventors who were about to usher in the present era of
submarine warfare: Simon Lake and John P. Holland.
CHAPTER VII

JOHN P. HOLLAND

W
hen the Merrimac rammed the Cumberland, burned the
Congress, and was fought to a standstill next day by the
little Monitor, all the world realized that there had been a
revolution in naval warfare. The age of the wooden warship was
gone forever, the day of the ironclad had come. And a twenty-year-
old Irish school-teacher began to wonder what would be the next
revolution; what new craft might be invented that would dethrone
the ironclad. This young Irishman’s name was John P. Holland, and
he decided to devote his life to the perfection of the submarine.

Like Robert Fulton, Admiral Von Tirpitz, and the Frenchman who
built the Rotterdam Boat in 1652, Holland relied on submarines to
break the power of the British fleet. Though born a British subject, in
the little village of Liscannor, County Clare in the year 1842, he had
seen too many of his fellow countrymen starved to death or driven
into exile not to hate the stupid tyranny that characterized England’s
rule of Ireland in those bitter, far-off days. He longed for the day of
Ireland’s independence, and that day seemed to be brought much
nearer by the American Civil War. Not only had many thousand brave
Irish-Americans become trained veterans but Great Britain and the
United States had been brought to the verge of war by the sinking of
American ships by the Alabama and other British-built, Confederate
commerce-destroyers. When that Anglo-American war broke out,
there would be an army ready to come over and free Ireland—if only
the troublesome British navy could be put out of the way. And
already the English were launching ironclad after ironclad to replace
their now useless steam-frigates and ships-of-the-line. It is no use
trying to outbuild or outfight the British navy above water, and John
P. Holland realized this in 1862, as several kings and emperors have,
before or since.

The Holland No. 1. Designed to carry a torpedo and fix it to


the bottom of a ship, on the general principle of Bushnell’s
Turtle.
Drawn by Lieutenant F. M. Barber, U. S. N., in 1875.

Though his friends in Cork kept laughing at him, Holland worked


steadily on his plans for a submarine boat, throughout the sixties.
Presently he came to America and obtained a job as school-teacher
in Paterson, New Jersey. There he built and launched his first
submarine in 1875. It was a sharp-pointed, little, cigar-shaped affair,
only sixteen feet long and two feet in diameter amidships. This craft
was designed to carry a torpedo and fix it to the bottom of a ship,
on the general principle of Bushnell’s Turtle. It was divided into four
compartments, with air-chambers fore and aft. Air-pipes led to
where Holland sat in the middle, with his head in a respirator shaped
like a diver’s helmet, and his feet working pedals that turned the
propellor.
There was nothing revolutionary about this Holland No. 1. A
similar underwater bicycle is said to have been invented by Alvary
Templo in 1826, and Drzewiecki used one at Odessa in 1877. But
Holland used his to teach himself how to build something better. Just
as the Wright brothers learned how to build and fly aeroplanes by
coasting down through the air from the tops of the Kitty Hawk sand-
hills in their motorless “glider,” so John P. Holland found how to
make and navigate submarines by diving under the surface of the
Passaic River and adjacent waters, and swimming around there in
his No. 1 and her successors.
The Holland No. 2 was launched in 1877 and became
immediately and prophetically stuck in the mud. She had a double
hull, the space between being used as a ballast-tank, whose
contents leaked constantly into the interior, and she was driven
intermittently by a four horse-power petroleum engine of primitive
design. After a series of trials that entertained his neighbors and
taught the inventor that the best place for a single horizontal rudder
is the stern, Holland took the engine out of the boat and sank her
under the Falls Bridge, where she lies to this day.
He then entered into negotiations with the Fenian Brotherhood,
a secret society organized for the purpose of setting up an Irish
republic by militant methods. Though not a Fenian himself, Holland
was thoroughly in sympathy with the brotherhood, and offered to
show them how they could get round, or rather under, the British
navy. You may have seen a once-familiar lithograph of a green-
painted superdreadnought of strange design flying the Crownless
Harp, and named the Irish battleship Emerald Isle. The only real
Irish warships of modern times, however, were the two submarines
Holland persuaded the Fenians to have him build at their expense.
Rear-Admiral Philip Hichborn, former Chief Constructor, U.S.N.,
said of these two boats:
“She (the earlier one) was the first submarine since Bushnell’s
time employing water ballast and always retaining buoyancy, in
which provision was made to insure a fixed center of gravity and a
Welcome to Our Bookstore - The Ultimate Destination for Book Lovers
Are you passionate about testbank and eager to explore new worlds of
knowledge? At our website, we offer a vast collection of books that
cater to every interest and age group. From classic literature to
specialized publications, self-help books, and children’s stories, we
have it all! Each book is a gateway to new adventures, helping you
expand your knowledge and nourish your soul
Experience Convenient and Enjoyable Book Shopping Our website is more
than just an online bookstore—it’s a bridge connecting readers to the
timeless values of culture and wisdom. With a sleek and user-friendly
interface and a smart search system, you can find your favorite books
quickly and easily. Enjoy special promotions, fast home delivery, and
a seamless shopping experience that saves you time and enhances your
love for reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!

ebooksecure.com

You might also like