Intro
This a review of Think Python 2e by Allen Downey.
This book is divided into 21 chapters and is about 257 pages long.
1 – Way of the Program 🥋
- The most important skill for a computer scientist is problem solving.
- A program is a sequence of instructions that specifies how to perform a computation.
- Formal languages are designed by people for specific applications.
- Evidence shows people respond to computers as if they are people (the media equation, Reeves & Nass 1996).
2 – Variables, Expressions, and Statements ⚽
- A variable is a name that refers to a value.
- An assignment creates new variables and gives them values, e.g.,
x = 2
. - An expression is a combination of values, variables, and operators, e.g.,
x + y
. - A statement is a unit of code that the Python interpreter can execute, e.g.,
print('hello world')
.
3 – Functions
- The expression in parentheses is called the argument of the function.
- A module is a file that contains a collection of related functions.
- A function definition specifies the name of a new function and the sequence of statements that execute when the function is called.
- To ensure that a function is defined before its first use, you have to know the order statements run, which is called the flow of execution.
- A parameter is what is defined in the function, and the argument is what is passed into the function.
- To keep track of which variables can be used, we can draw stack diagrams.
- Each function is represented by a frame.
- If an error occurs, a list of functions is printed, which is called a traceback.
- Fruitful 🍇 functions return something; void 🌌 functions don’t.
4 – Interface Design
- Turtle 🐢 module.
- Wrapping a piece of code in a function is called encapsulation 💊.
- A docstring 📄 is a string at the beginning of a function that explains the interface, like:
def x: """this function does something"""
5 – Conditionals and Recursion 🔁
- Floor division operator
//
divides two numbers and rounds down to an integer; an alternative is the modulus operator%
, which divides two numbers and returns the remainder. - Three logical operators:
and
,or
, andnot
. - The bottom of a recursive function stack is called the base case as there are no more frames to call.
6 – Fruitful Functions 🍓
- Code that’s never reached is called dead code 😵.
- To deal with increasingly complex programs, you can try incremental development. This is when you add and test a small amount of code each time.
- Scaffolding 🚧 is when you have code that is helpful for building the program but not part of the final product.
- Following the flow of execution is one way to read a program; the other way is to do the ‘leap of faith’, which is when you assume the function works correctly.
7 – Iteration 🔂
- Reassignment is when you make an existing variable refer to a new value; equality is a symmetric relationship, and assignment is not.
>>> x = 5 >>> x 5 >>> x = 7 >>> x 7
- An algorithm is a mechanical process for solving a category of problems.
- Exercise 7.3 – Ramanujan’s infinite series:
import math def estimate_pi(): sum = 0 epsilon = math.pow(10, -15) k = 0 i = 1 # initialize i, the value doesn't matter while i > epsilon: i = math.factorial(4 * k) * (1103 + 26390 * k) \ / (math.pow(math.factorial(k), 4) * math.pow(396, 4 * k)) sum += i k += 1 inverse = 2 * math.sqrt(2) * sum / 9801 return 1 / inverse print(estimate_pi()) print(math.pi) print(estimate_pi() - math.pi)
8 – Strings 🧵
- A string is a sequence of characters.
- Traversal is when you visit and perform computation on each character.
- A segment of a string is called a slice.
- Python 🐍 strings are immutable.
- A method call is called an invocation.
9 – Word Play
- If you see that
uses_all
was an instance of a previously solved problem, you are practicing a program development plan called reduction to a previously solved problem.
10 – Lists
- A list is a sequence of values; you can have nested lists.
- Lists are mutable.
- You can traverse a list with a
for
loop.
def add_all(t): total = 0 for x in t: total += x return total
- As the loop runs,
total
accumulates the sum of elements. A variable used like this is sometimes called an accumulator.
>>> t = [1, 2, 3] >>> sum(t) 6
- An operation like above combines a sequence of elements into a single value and is sometimes called
reduce
. - An operation like
capitalize_all
is sometimes called a map as it ‘maps’ a function onto each element in a list. - You can use
pop
,del
, orremove
to delete elements from a list. - The association of a variable within an object is called a reference.
- An object with more than one reference has more than one name, and we can say that the object is aliased.
11 – Dictionaries 📚
- A dictionary is like a list but more general. A dictionary represents a mapping from keys to values.
- Hashtable explanation on page 251.
- Given a dictionary
d
and a keyk
, we can find a corresponding valuev = d[k]
; this operation is called a lookup. raise
statement causes an exception.- A singleton is a list that contains a single element.
- Dictionary is implemented using a hashtable, which means keys must be hashable (e.g., lists cannot be keys); keys must be immutable to maintain idempotent lookups.
- Recursive Fibonacci algorithm has a call graph that shows repeated computed values.
- A previously computed value that’s stored for later use is called a memo.
# memoized version of fibonacci known = {0:0, 1:1} def fibonacci(n): if n in known: return known[n] res = fibonacci(n-1) + fibonacci(n-2) known[n] = res return res
- Variables in
__main__
are sometimes called global as they can be accessed from any function. - It’s common to use global variables as flags.
12 – Tuples 👨👨👧👧
- A tuple is a sequence of values; tuples are immutable.
>>> t = 'a', 'b', 'c' >>> t ('a', 'b', 'c')
- To create a tuple with a single element, you have to include a final comma.
>>> u = 'a', >>> u ('a',)
- Tuple assignment – no need for a third variable when swapping the values of two variables.
>>> a, b = b, a
divmod
takes two arguments and returns a tuple of two values: the quotient and remainder.
>>> t = divmod(7, 3) >>> t (2, 1)
- A parameter name that begins with
*
gathers arguments into a tuple.
def printall(*args): print(args)
- The complement of gather is scatter (use
*
operator).
>>> t = (7,3) >>> divmod(*t) # scatter the tuple
zip
function takes two or more sequences and returns a list of tuples where each tuple contains one element from each sequence.- Dictionaries 📚 have a method called
items
that returns a sequence of tuples, where each tuple is a key-value pair. - Compound data structures are useful but prone to ‘shape errors’.
13 – Data Structure Selection
- Prefixes: strings, list of strings, tuple of strings.
- Suffixes: list / histogram (dictionary).
- Mapping from prefix to suffix: dictionary.
14 – Files 📂
- Persistence is when some data is kept in permanent storage.
os
module has functions for working with files and directories, e.g.,os.cwd
gets the name of the current directory.- Sometimes errors happen when reading/writing files; handling an exception with a
try
statement is called catching an exception. - A database is a file that’s organized for storing data; Python has a module called dbm.
pickle
module can translate any type of object into a string suitable for storage in a database.
15 – Classes and Objects
- OOP uses programmer-defined types to organize both code and data.
- A programmer-defined type is also called a class.
- A state diagram that shows an object and its attributes is called an object diagram.
- An object that’s an attribute of another object is embedded.
- Shallow copy copies the object and any references it contains, but not embedded objects.
16 – Classes and Functions
- Prototype and patch is a type of development plan that deals with complex problems by starting with a simple prototype and increasingly dealing with complications.
- Pure functions don’t have side effects.
- Functions that modify objects they get as parameters can be called modifiers.
- The author recommends you resort to writing pure functions whenever possible and use modifiers only if there’s a compelling advantage. This approach is called the functional programming style.
- An alternative style to prototype and patch is designed development, where high-level insight into the problem can make programming easier.
- Invariants are conditions that should always be true.
17 – Classes and Methods
- A method is a function that’s associated with a particular class.
- There are two syntactic differences: 1) they’re defined inside a class definition to make the relationship between the class and method explicit.
- The syntax for invoking a method is different.
- Positional argument is an argument that doesn’t have a default value.
sketch(parrot, cage, dead=True)
parrot
andcage
are positional,dead
is a keyword argument.__init__
is a special method that’s invoked when an object is instantiated.__str__
is a special method that’s supposed to return a string representation of an object.- Changing the behavior of an operator so that it works with programmer-defined types is called operator overloading.
- A type-based dispatch dispatches a computation to different methods based on the type of arguments.
- Functions that work with several types are called polymorphic. Polymorphism 🐑 can facilitate code reuse.
- A design principle that helps make software more maintainable is to keep the interface separate from the implementation.
18 – Inheritance
- Inheritance is the ability to define a new class that’s a modified version of an existing class.
- A veneer is a thin method that uses another method without doing much work.
- When a new class inherits from an existing one, the existing one is called the parent and the new class is called the child.
- Pros of inheritance include code reuse; cons of inheritance are that it sometimes makes programs difficult to read.
- When objects in one class contain references to objects in another class, this relationship is called HAS-A.
- When one class might inherit from another, this relationship is called IS-A.
- These relationships can be shown in a class diagram.
- Data encapsulation (aka data hiding) is the mechanism where implementation details of a class are hidden from a user.
19 – The Goodies
- Conditional expressions:
y = math.log(x) if x > 0 else float('nan')
- List comprehensions:
# without LC def capitalize_all(t): res = [] for s in t: res.append(s.capitalize()) return res # with LC def capitalize_all(t): return [s.capitalize() for s in t]
- Generator expressions are similar to LCs but with parentheses instead of [].
>>> g = (x**2 for x in range(5))
- Knows how to iterate through a sequence of values but waits to be asked to do so.
any
– takes a sequence of Booleans and returns True if any value is True.
>>> any([False, False, True]) True
all
– returns True if every element of a sequence is True.- A set behaves like a collection of dictionary keys with no values.
def has_duplicates(t): return len(set(t)) < len(t)
- A
Counter
is a natural way to represent a multiset (mathematical idea).
from collections import Counter def is_anagram(w1, w2): return Counter(w1) == Counter(w2)
defaultdict
is like a dictionary, but if you’re trying to access a key that doesn’t exist, it will create one on the fly.- A function used to create objects is sometimes called a factory.
20 – Debugging
- Infinite recursion can cause a ‘Maximum recursion depth exceeded’ error.
- If you’re stuck on a bug, maybe go for a walk.
21 – Algorithm Analysis
- Analysis of algorithms is a branch of CS that studies the performance of algorithms, especially their runtime and space requirements.
- Relative performance might depend on details of the dataset; one way to avoid this is to analyze the worst-case scenario.
- The leading term is the term with the highest exponent.
- In general, we expect an algorithm with a smaller leading term to be a better algorithm for large problems, but for small problems, there may be a crossover point.
- An order of growth is a set of functions whose growth behavior is considered equivalent.
- Some examples include O(1) constant, O(logn) (logarithmic for any base), O(n) linear, O(n log n) linearithmic, O(n2) quadratic, O(n3) cubic, O(cn) exponential (for any c).
- In Python 🐍, most arithmetic operations are constant time. Indexing operations are also constant time.
- A
for
loop that traverses a sequence/dictionary is usually linear. - Python dictionaries are implemented using hashtables.
Conclusion
Overall, I liked this book and recommend it to anyone who is interested in the Python programming language. It is written in an easy-to-read style, and the examples are quite manageable.
Additional reading
You can read Think Python online for free 🥰
Leave a Reply