Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Markdown/01_Introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ complete program. These files are extracted from the chapters and live in the
`Examples/` directory of the
[source repository](https://github.com/BruceEckel/ThinkingInPython), one folder
per chapter, named to match the chapter. So a block tagged `# trace.py` in the
Decorators chapter is the file `Examples/08_Decorators/trace.py`. The examples
Decorators chapter is the file `Examples/12_Decorators/trace.py`. The examples
that read a data file, or that span several files, keep them together in the same
chapter folder.

Expand Down
4 changes: 2 additions & 2 deletions Markdown/02_A_Python_Tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ if response == "yes":
print("continuing...")
```

The '`\#`' denotes a comment that goes until the end of the line, just like
The '`#`' denotes a comment that goes until the end of the line, just like
C++ and Java '`//`' comments.

First notice the `if` statement.
Expand Down Expand Up @@ -286,7 +286,7 @@ The one exception is class names, which are "pascal-cased," starting with a
capital letter, without underscores and capitalizing intermediate words. For
example: `ThisIsMyClass`.

[PEP 8]([PEP 8](https://www.python.org/dev/peps/pep-0008/) covers all manner
[PEP 8](https://www.python.org/dev/peps/pep-0008/) covers all manner
of style issues. These can be automatically applied to your code (or at least,
pointed out) using tools such as
[AutoPEP8](https://pypi.python.org/pypi/autopep8) or
Expand Down
3 changes: 2 additions & 1 deletion Markdown/03_Containers_and_Control_Flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ with open(path) as f:
os.remove(path)
```

This is the explicit-finalizer approach mentioned under Cleanup. Anything that
This is the explicit-finalizer approach from the [Initialization and
Cleanup](07_Initialization_and_Cleanup.md) chapter. Anything that
acquires a resource (a file, a lock, a network connection) can be a context
manager.

Expand Down
8 changes: 5 additions & 3 deletions Markdown/04_Functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ print(a_function("yes"))

Notice there is no type information in the function signature: all it
specifies is the name of the function and the argument identifiers, but no
argument types or return types. Python is a *structurally-typed* language,
which means it puts the minimum possible requirements on typing. For example,
you could pass and return different types from the same function:
argument types or return types. Python is dynamically typed, which means it
enforces type constraints at runtime. For example,
different types can be both passed to and returned from the same function:

```python
# different_returns.py
Expand Down Expand Up @@ -162,6 +162,8 @@ square = lambda n: n * n # usually prefer def
print(square(9)) # 81
```

Python's lambdas are rather constrained because they comprise a single expression.
For anything more complicated you are expected to write a separate function.

## Unpacking Arguments

Expand Down
2 changes: 1 addition & 1 deletion Markdown/05_Modules_and_Packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The code at the end of the file starts with an `if` clause which checks to see
if something called `__name__` is equivalent to `__main__`. In Python, any
identifier that begins and ends with double underscores is special in some
way. The reason for the `if` is that any file can also be used as a library
module within another program (modules are described shortly). In that case,
module within another program. In that case,
you just want the classes defined, but you don't want the code at the bottom
of the file to be executed. This particular `if` statement is only true when
you are running this file directly. That is, `__name__` is `__main__` when you
Expand Down
16 changes: 8 additions & 8 deletions Markdown/06_Classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,20 @@ This seems a little strange coming from C++ or Java where you must decide
ahead of time how much space your object is going to occupy, but it turns out
to be a very flexible way to program. If you declare fields using the C++/Java
style, they implicitly become class level fields (similar to the static fields
in C++/Java)
in C++/Java).

## Inheritance

Because Python is dynamically typed, it doesn't really care about
interfaces -all it cares about is applying operations to objects (in
interfaces: all it cares about is applying operations to objects (in
fact, Java's `interface` keyword would be wasted in Python). This
means that inheritance in Python is different from inheritance in C++ or
Java, where you often inherit simply to establish a common interface. In
Python, the only reason you inherit is to inherit an implementation, to
re-use the code in the base class.

To inherit from a class, you must tell Python to bring that class into your
new file. Python controls its name spaces as aggressively as Java does, and in
new file. Python controls its namespaces as aggressively as Java does, and in
a similar fashion (albeit with Python's penchant for simplicity). Every time
you create a file, you implicitly create a module (which is like a package in
Java) with the same name as that file. Thus, no `package` keyword is needed in
Expand All @@ -88,7 +88,7 @@ You inherit a class (or classes, since Python supports multiple inheritance)
by listing the name(s) of the class inside parentheses after the name of
the inheriting class. Note that the `Simple` class, which resides in
the file (and thus, module) named `simple_class` is brought into this
new name space using an `import` statement:
new namespace using an `import` statement:

```python
# simple2.py
Expand Down Expand Up @@ -130,19 +130,19 @@ override a method but still want the base-class version, call it through
`super()`, as the overridden `show()` does.

In `__main__`, you will see (when you run the program) that the
base-class constructor is called. You can also see that the `show_msg(
)` method is available in the derived class, just as you would expect
base-class constructor is called. You can also see that the `show_msg()`
method is available in the derived class, just as you would expect
with inheritance.

The class `Different` also has a method named `show()`, but this
class is not derived from `Simple`. The `f()` method defined in
`__main__` demonstrates weak typing: all it cares about is that
`__main__` demonstrates duck typing: all it cares about is that
`show()` can be applied to `obj`, and it doesn't have any other
type requirements. You can see that `f()` can be applied equally to
an object of a class derived from `Simple` and one that isn't, without
discrimination. If you're a C++ programmer, you should see that the
objective of the C++ `template` feature is exactly this: to provide
weak typing in a strongly-typed language. Thus, in Python you
duck typing in a statically-typed language. Thus, in Python you
automatically get the equivalent of templates, without having to learn
that particularly difficult syntax and semantics.

Expand Down
2 changes: 1 addition & 1 deletion Markdown/07_Initialization_and_Cleanup.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Initialization and Cleanup

A constructor sets up an object, and you saw `__init__()` do that above. Two
A constructor sets up an object, and you saw `__init__()` do that in the [Classes](06_Classes.md) chapter. Two
parts of an object's lifetime surprise programmers coming from C++ or Java: how
class-level attributes behave, and how and when objects are cleaned up.

Expand Down
4 changes: 2 additions & 2 deletions Markdown/08_Static_Type_Checking.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Static Type Checking

The functions earlier in this chapter declare no types. C++ and Java make you
The functions in the earlier chapters declare no types. C++ and Java make you
declare the type of everything, and they check those types before the program
runs. Python checks types at run time, only when an operation is actually
attempted, and so far this chapter has leaned on that freedom.
attempted, and the book so far has leaned on that freedom.

On a small program you do not miss the declarations. On a large one you start to.
A type error that a compiler would have caught now waits until the code runs, and
Expand Down
4 changes: 1 addition & 3 deletions Markdown/12_Decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The output is:
-> add(2, 3)
<- add = 5

The `@trace` above `add` is just sugar. It means:
The `@trace` above `add` means:

add = trace(add)

Expand Down Expand Up @@ -366,8 +366,6 @@ Adding a new extra means adding one class. Changing the price of an extra means
changing one number, in one place. Compare that to a class per combination, where
a price change touches every class that includes that extra.

A test fixes the behavior:

```python
# test_coffee.py
from coffee import Cappuccino, Decaf, Espresso, ExtraShot, Whipped
Expand Down
14 changes: 7 additions & 7 deletions Markdown/13_Comprehensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The comprehension has three parts:
- If the member is an integer then it is passed to the output
expression, squared, to become a member of the output list.

Much the same results can be achieved using the built in functions,
Much the same results can be achieved using the built-in functions,
`map`, `filter` and the anonymous `lambda` function.

The filter function applies a predicate to a sequence:
Expand All @@ -67,7 +67,7 @@ The above example involves function calls to `map`, `filter`,
expensive. Furthermore the input sequence is traversed through twice and
an intermediate list is produced by filter.

The list comprehension is enclosed within a list so, it is immediately
The list comprehension is enclosed within a list, so it is immediately
evident that a list is being produced. There is only one function call
to `isinstance` and no call to the cryptic `lambda`; instead the list
comprehension uses a conventional iterator, an expression and an if
Expand All @@ -88,7 +88,7 @@ following list:
[ 0, 1, 0 ],
[ 0, 0, 1 ] ]

Would be more efficient to represent the structure as a tuple of tuples,
It would be more efficient to represent the structure as a tuple of tuples,
but the whole point of this example is to use lists.

The above matrix can be generated by the following comprehension:
Expand Down Expand Up @@ -121,14 +121,14 @@ for r in rest_files:
## Set Comprehensions

Set comprehensions allow sets to be constructed using the same
principles as list comprehensions, the only difference is that resulting
principles as list comprehensions. The only difference is that the resulting
sequence is a set.

Say we have a list of names. The list can contain names which only
differ in the case used to represent them, duplicates and names
consisting of only one character. We are only interested in names longer
then one character and wish to represent all names in the same format:
The first letter should be capitalised, all other characters should be
than one character and wish to represent all names in the same format:
The first letter should be capitalized; all other characters should be
lower case.

Given the list:
Expand Down Expand Up @@ -158,7 +158,7 @@ The dictionary currently distinguishes between upper and lower case
characters.

The following is inefficient: If both a lower case and upper case
character exists then the entry in the new dictionary is updated twice
character exists, then the entry in the new dictionary is updated twice.

We require a dictionary in which the occurrences of upper and lower case
characters are combined:
Expand Down
26 changes: 9 additions & 17 deletions Markdown/16_The_Pattern_Concept.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ describing a succession of different types of categories:
attempt to be general.
3. **Standard Design**: a way to solve this *kind* of problem. A design
that has become more general, typically through reuse.
4. **Design Pattern**: how to solve an entire class of similar problem.
4. **Design Pattern**: how to solve an entire class of similar problems.
This usually only appears after applying a standard design a number
of times, and then seeing a common pattern throughout these
applications.
Expand Down Expand Up @@ -167,7 +167,7 @@ and say "clearly, you need a structural pattern here," so that
classification doesn't lead me to a solution (I'll readily admit that I
may be missing something here).

I've labored for awhile with this problem, first noting that the
I've labored for a while with this problem, first noting that the
underlying structure of some of the GoF patterns are similar to each
other, and trying to develop relationships based on that similarity.
While this was an interesting experiment, I don't think it produced much
Expand All @@ -183,9 +183,7 @@ connecting these structures with patterns (or I may come up with a
different approach altogether; this is still in its formative stages).

Here^[This list includes suggestions by Kevlin Henney, David Scott, and
others.] is the present list of candidates, only some of which will make it
to the final list. Feel free to suggest others, or possibly
relationships with patterns.
others.] is the present list of candidates:

- **Encapsulation**: self containment and embodying a model of usage
- **Gathering**
Expand All @@ -204,9 +202,7 @@ medium" (May be a variation on Proxy).

## Design Principles

When I put out a call for ideas, a number of suggestions came back which
turned out to be very useful, but different than the above classification, and
I realized that a list of design principles is at least as important as design
A list of design principles is at least as important as design
structures, but for a different reason: these allow you to ask questions about
your proposed design, to apply tests for quality.

Expand Down Expand Up @@ -235,8 +231,7 @@ your proposed design, to apply tests for quality.
not when there's nothing left to add, but when there's nothing left to
remove".].
- *Simplicity before generality*^[From an email from Kevlin Henney.].
(A variation of *Occam's Razor*,
which says "the simplest solution is the best"). A common problem we
A common problem we
find in frameworks is that they are designed to be general purpose
without reference to actual systems. This leads to a dizzying array
of options that are often unused, misused or just not useful.
Expand All @@ -246,17 +241,14 @@ your proposed design, to apply tests for quality.
So, this principle acts as the tie breaker between otherwise equally
viable design alternatives. Of course, it is entirely possible that
the simpler solution is the more general one.
- *Reflexivity* (my suggested term). One abstraction per class, one
- *Reflexivity*. One abstraction per class, one
class per abstraction. Might also be called Isomorphism.
- *Once and once only*: Avoid duplication of logic and structure
where the duplication is not accidental, ie where both pieces of
where the duplication is not accidental, i.e., where both pieces of
code express the same intent for the same reason.

In the process of brainstorming this idea, I hope to come up with a
small handful of fundamental ideas that can be held in your head while
you analyze a problem. However, other ideas that come from this list may
end up being useful as a checklist while walking through and analyzing
your design.
This is a small handful of fundamental ideas that can be held in your
head while walking through and analyzing your design.

## Further Reading

Expand Down
2 changes: 1 addition & 1 deletion Markdown/19_Application_Frameworks.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ hierarchy. This is the same trade-off seen in the Function Objects chapter: a
hook that holds no state is usually better as a function than as a method to
override.

The behavior to test is the same for both: the fixed algorithm calls the steps in
We want to test that algorithm calls the steps in
order, twice. Recording steps make that order visible:

```python
Expand Down
2 changes: 1 addition & 1 deletion Markdown/20_Fronting_for_an_Implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ are:
3. `Protection proxy`. Used when you don't want the client programmer
to have full access to the proxied object.
4. `Smart reference`. To add additional actions when the proxied
object is accessed. For example, or to keep track of the number of
object is accessed. For example, to keep track of the number of
references that are held for a particular object, in order to
implement the *copy-on-write* idiom and prevent object aliasing. A
simpler example is keeping track of the number of calls to a
Expand Down
2 changes: 1 addition & 1 deletion Markdown/21_State_Machines.md
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ covered in [Fronting for an Implementation](20_Fronting_for_an_Implementation.md
changes the kind of response to its `hello()` method depending on
what kind of `Mood` it's in. Add an additional kind of `Mood`
called `Prozac`.
5. Create a simple copy-on write implementation.
5. Create a simple copy-on-write implementation.
6. Apply `transition_table.py` to the "Washer" problem.
7. Create a *StateMachine* system whereby the current state along with
input information determines the next state that the system will be
Expand Down
4 changes: 2 additions & 2 deletions Markdown/23_Factory.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ for shape in shapes:
```

The `factory()` takes an argument that allows it to determine what
type of `Shape` to create; it happens to be a `String` in this case
type of `Shape` to create; it happens to be a string in this case
but it could be any set of data. The `factory()` is now the only
other code in the system that needs to be changed when a new type of
`Shape` is added (the initialization data for the objects will
Expand Down Expand Up @@ -129,7 +129,7 @@ Also note that in `shape_name_gen()` the statement:

types = Shape.__subclasses__()

Is only executed when the generator object is produced; each time the
is only executed when the generator object is produced; each time the
`next()` method of this generator object is called (which, as noted
above, may happen implicitly), only the code in the `for` loop will be
executed, so you don't have wasteful execution (as you would if this
Expand Down
2 changes: 1 addition & 1 deletion Markdown/25_Changing_the_Interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ client programmer doesn't really need to see, then you can create an
interface that is useful for the client programmer and that only
presents what's necessary.

Façade is often implemented as singleton abstract factory. Of course,
Façade is often implemented as a singleton abstract factory. Of course,
you can easily get this effect by creating a class containing `static`
factory methods:

Expand Down
6 changes: 3 additions & 3 deletions Markdown/26_Observer.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ create and use. All you have to say is:

myMethod = synchronized(myMethod)

To surround your method with a mutex.
to surround your method with a mutex.

`synchronize()` is a convenience function that applies
`synchronized()` to an entire class, either all the methods in the
Expand Down Expand Up @@ -541,8 +541,8 @@ the only connection the `Observer`s have with `Flower`s is the

### A Visual Example of Observers

This is the `ColorBoxes` example from *Thinking in Java*. A grid of boxes each
start with some color. Every box observes a shared `Observable`. When one box is
This is the `ColorBoxes` example from *Thinking in Java*. A grid of boxes, each
starting with some color. Every box observes a shared `Observable`. When one box is
"clicked," the `Observable` notifies every box, and each box adjacent to the
clicked one changes its color to match it.

Expand Down
2 changes: 1 addition & 1 deletion Markdown/27_Multiple_Dispatching.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ get particularly messy. For example, consider a system that parses and
executes mathematical expressions. You want to be able to say `Number +
Number`, `Number \* Number`, etc., where `Number` is the base class
for a family of numerical objects. But when you say `a + b`, and you
don't know the exact type of either `a` or `b`, so how can you get
don't know the exact type of either `a` or `b`, how can you get
them to interact properly?

The answer starts with something you probably don't think about: Python
Expand Down
4 changes: 4 additions & 0 deletions NOTES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
- Consider TKInter for simulation chapter, or any example that might benefit from graphics.
Maybe it's not perfect but this isn't a book about GUIs, and there's
no installation hassle with TKInter.
Ideally everything should be pure-functional and only produce return values
*except* the function that takes the values and displays them; that's all that function should do.
First do '### A Visual Example of Observers' in the Observer chapter and let me evaluate the result
before doing any other examples.

- Indexing using Leanpub format, before publishing to leanpub

Expand Down
Loading
Loading