Python Distilled 1st edition - eBook PDF instant download
Python Distilled 1st edition - eBook PDF instant download
download
https://ebooksecure.com/download/python-distilled-ebook-pdf/
http://ebooksecure.com/product/ebook-pdf-building-python-
programs-1st-edition/
http://ebooksecure.com/product/python-for-dummies-1st-edition-
pdf-version/
https://ebooksecure.com/download/problem-solving-and-python-
programming-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/
https://ebooksecure.com/download/data-structures-algorithms-in-
python-ebook-pdf/
https://ebooksecure.com/download/r-and-python-for-oceanographers-
a-practical-guide-with-applications-ebook-pdf/
http://ebooksecure.com/product/ebook-pdf-starting-out-with-
python-4th-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
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 questions about sales outside the U.S., please contact intlcs@pearson.com.
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
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
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
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.
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.
Certain environments may display a different prompt. The following output is from
ipython (an alternate shell for Python):
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.
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.
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 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
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.
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
Operation Description
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.
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
Operator Description
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.
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')
If you are assigning a value in combination with a test, use a conditional expression:
maxval = a if a > b else 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)
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
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
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'
)
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
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.
Method Description
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)
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
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
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')
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']
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(','))
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
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)
>>>
>>> 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
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
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
}
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
}
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
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
total_shares = Counter()
for name, shares, _ in portfolio:
total_shares[name] += shares
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
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}')
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)
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
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)
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
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)
...
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
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
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)
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 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)
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
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 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)
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
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.
C. S. S. Hundley.
The Only Submarine to sink a Hostile Warship before the Outbreak of
the Present War.
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.
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.
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.
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.
ebooksecure.com