From c001902dfae571e7b4addaf508955f9ee93dd56d Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:06:54 -0600 Subject: [PATCH 01/14] Proofread ch 01-03: fix stale refs, markdown typos, log one finding - 01 Introduction: example path 08_Decorators -> 12_Decorators (stale after the chapter renumber). - 02 A Python Tour: remove stray backslash in the `#` code span; fix the malformed nested PEP 8 link. - 03 Containers and Control Flow: "mentioned under Cleanup" now points at the Initialization and Cleanup chapter (Cleanup split out in the restructure). - Logged one confusing-sentence rewrite (03:38) to PROOFREADING_FINDINGS.md. Co-Authored-By: Claude Opus 4.8 --- Markdown/01_Introduction.md | 2 +- Markdown/02_A_Python_Tour.md | 4 +- Markdown/03_Containers_and_Control_Flow.md | 3 +- PROOFREADING_FINDINGS.md | 24 +++++++++ PROOFREADING_PROGRESS.md | 63 ++++++++++++++++++++++ 5 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 PROOFREADING_FINDINGS.md create mode 100644 PROOFREADING_PROGRESS.md diff --git a/Markdown/01_Introduction.md b/Markdown/01_Introduction.md index 30460836..35351f02 100644 --- a/Markdown/01_Introduction.md +++ b/Markdown/01_Introduction.md @@ -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. diff --git a/Markdown/02_A_Python_Tour.md b/Markdown/02_A_Python_Tour.md index 1b2c9932..7a150747 100644 --- a/Markdown/02_A_Python_Tour.md +++ b/Markdown/02_A_Python_Tour.md @@ -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. @@ -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 diff --git a/Markdown/03_Containers_and_Control_Flow.md b/Markdown/03_Containers_and_Control_Flow.md index 616d325d..4236761b 100644 --- a/Markdown/03_Containers_and_Control_Flow.md +++ b/Markdown/03_Containers_and_Control_Flow.md @@ -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. diff --git a/PROOFREADING_FINDINGS.md b/PROOFREADING_FINDINGS.md new file mode 100644 index 00000000..f8e3482e --- /dev/null +++ b/PROOFREADING_FINDINGS.md @@ -0,0 +1,24 @@ +# Proofreading Findings (for review) + +Confusing or awkward sentences flagged during the prose pass, with proposed +rewrites. These are NOT applied. The user decides which to take. + +Mechanical fixes (spelling, doubled words, em-dashes, run-ons) are applied +directly and committed per chapter, so they are not listed here. + +Format per entry: + +> **NN_Chapter.md:LINE** +> Original: ... +> Proposed: ... +> Why: ... + +--- + +> **03_Containers_and_Control_Flow.md:38-39** +> Original: "It's as if Python is designed so that you only need to press the +> keys that absolutely must." +> Proposed: "It's as if Python is designed so that you only press the keys that +> are strictly necessary." +> Why: "the keys that absolutely must" is an incomplete clause (must *what?*), +> so it reads as if a word is missing. diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md new file mode 100644 index 00000000..913f0351 --- /dev/null +++ b/PROOFREADING_PROGRESS.md @@ -0,0 +1,63 @@ +# Proofreading Progress + +Checkpoint for the prose proofreading pass. On restart, read this first, find +the first unchecked chapter, and continue from there. Update the checkboxes and +the "Last updated" line before ending each iteration. + +Last updated: iteration 1 done (chapters 01-03), committed on branch +`proofread/prose-pass`. +Next action: proofread chapters 04-06. + +## Policy + +- Work 2-3 chapters per iteration. +- AUTO-FIX (in both Markdown and, if a code block changes, the matching + Examples/ file): spelling, doubled words, `it's`/`its` and similar, spacing, + and the global style rules: no em-dashes (`--` or the character), break + run-ons into short sentences, italics only to introduce a new term. +- DO NOT silently rewrite voice. For confusing sentences or awkward phrasing, + append an entry to `PROOFREADING_FINDINGS.md` (chapter, original, proposed + rewrite) for the user to approve later. Do not change the prose. +- Only touch prose. Do not change code blocks except to fix a comment typo; + if a code block changes, sync the matching `Examples/` file. +- After each iteration: run `uv run python tools/extract_examples.py` (drift + must stay in sync), update this file, then commit. Stage explicitly + (`git add Markdown PROOFREADING_PROGRESS.md PROOFREADING_FINDINGS.md` plus any + touched `Examples/` paths). Do NOT `git add -A` (an unrelated `_TODO.md` edit + is in the tree and must not be committed). + +## Chapters + +- [x] 01 Introduction +- [x] 02 A Python Tour +- [x] 03 Containers and Control Flow +- [ ] 04 Functions +- [ ] 05 Modules and Packages +- [ ] 06 Classes +- [ ] 07 Initialization and Cleanup +- [ ] 08 Static Type Checking +- [ ] 09 Testing +- [ ] 10 Data Classes as Types +- [ ] 11 Functional Error Handling +- [ ] 12 Decorators +- [ ] 13 Comprehensions +- [ ] 14 Metaprogramming +- [ ] 15 Rethinking Objects +- [ ] 16 The Pattern Concept +- [ ] 17 Messenger +- [ ] 18 Singleton +- [ ] 19 Application Frameworks +- [ ] 20 Fronting for an Implementation +- [ ] 21 State Machines +- [ ] 22 Iterators +- [ ] 23 Factory +- [ ] 24 Function Objects +- [ ] 25 Changing the Interface +- [ ] 26 Observer +- [ ] 27 Multiple Dispatching +- [ ] 28 Visitor +- [ ] 29 Pattern Refactoring +- [ ] 30 Simulation + +When all are checked, stop the loop (no further ScheduleWakeup). The user +reviews PROOFREADING_FINDINGS.md and decides which rewrites to apply. From fb6c5bcb931db6b8dad0af3c74300bdef50cb394 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:13:10 -0600 Subject: [PATCH 02/14] Proofread ch 04-06: fix typos in 05-06, log 4 findings - 05 Modules and Packages: drop stale "(modules are described shortly)" aside (this is the modules chapter; they are introduced at the top). - 06 Classes: "interfaces -all" -> "interfaces: all"; "name space(s)" -> "namespace(s)" (matches ch 05); add a missing period; repair the broken `show_msg()` inline-code span split across a line. - Logged 4 findings for review: "structurally-typed" and "implicit global variable" (ch 04), "weak typing" terminology (ch 06), and the redundant module re-explanation in ch 06's Inheritance section. Co-Authored-By: Claude Opus 4.8 --- Markdown/05_Modules_and_Packages.md | 2 +- Markdown/06_Classes.md | 12 ++++----- PROOFREADING_FINDINGS.md | 42 +++++++++++++++++++++++++++++ PROOFREADING_PROGRESS.md | 10 +++---- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/Markdown/05_Modules_and_Packages.md b/Markdown/05_Modules_and_Packages.md index d4877795..006434fa 100644 --- a/Markdown/05_Modules_and_Packages.md +++ b/Markdown/05_Modules_and_Packages.md @@ -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 diff --git a/Markdown/06_Classes.md b/Markdown/06_Classes.md index 6dc8bf43..008d1ac2 100644 --- a/Markdown/06_Classes.md +++ b/Markdown/06_Classes.md @@ -53,12 +53,12 @@ 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 @@ -66,7 +66,7 @@ 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 @@ -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 @@ -130,8 +130,8 @@ 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 diff --git a/PROOFREADING_FINDINGS.md b/PROOFREADING_FINDINGS.md index f8e3482e..455f450d 100644 --- a/PROOFREADING_FINDINGS.md +++ b/PROOFREADING_FINDINGS.md @@ -22,3 +22,45 @@ Format per entry: > are strictly necessary." > Why: "the keys that absolutely must" is an incomplete clause (must *what?*), > so it reads as if a word is missing. + +--- + +> **04_Functions.md:23** (conceptual) +> Original: "Python is a *structurally-typed* language, which means it puts the +> minimum possible requirements on typing." +> Proposed: "Python is *dynamically typed*, so it puts the minimum possible +> requirements on typing." (or frame the example as *duck typing*) +> Why: Python is dynamically typed; "structural typing" is the Protocol concept +> used in the Static Type Checking and Rethinking Objects chapters. Calling the +> language "structurally-typed" here is inaccurate and clashes with that usage. + +--- + +> **04_Functions.md:97** (conceptual / incorrect) +> Original: "Thus, a default value creates an implicit global variable." +> Proposed: "Thus a mutable default persists between calls: it is created once, +> at definition time, and lives on the function, not recreated on each call." +> Why: the shared default is not a global variable. It is one object bound to +> the function object. The current sentence states something false. + +--- + +> **06_Classes.md:139 and :145** (terminology) +> Original: "demonstrates weak typing" ... "to provide weak typing in a +> strongly-typed language." +> Proposed: "demonstrates duck typing" ... "to provide duck typing in a +> statically-typed language." +> Why: Python is strongly typed (no implicit coercion), just dynamic. What +> `f()` shows is duck typing / polymorphism, not "weak typing." Line 60 of the +> same chapter already (correctly) says "Python is dynamically typed," so the +> "weak typing" wording is also internally inconsistent. + +--- + +> **06_Classes.md:67-91** (structural redundancy) +> The Inheritance section re-explains modules, `import`, `from module import +> name(s)`, and PYTHONPATH/CLASSPATH at length. All of that is now covered in +> the preceding Modules and Packages chapter (05), so post-split it is +> redundant here. Suggest trimming to the one point inheritance needs: you +> import the base class before subclassing it (as `simple2.py` imports +> `Simple`). Flagging rather than cutting, since it is a sizable removal. diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index 913f0351..dac16794 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 1 done (chapters 01-03), committed on branch +Last updated: iteration 2 done (chapters 04-06), committed on branch `proofread/prose-pass`. -Next action: proofread chapters 04-06. +Next action: proofread chapters 07-09. ## Policy @@ -31,9 +31,9 @@ Next action: proofread chapters 04-06. - [x] 01 Introduction - [x] 02 A Python Tour - [x] 03 Containers and Control Flow -- [ ] 04 Functions -- [ ] 05 Modules and Packages -- [ ] 06 Classes +- [x] 04 Functions +- [x] 05 Modules and Packages +- [x] 06 Classes - [ ] 07 Initialization and Cleanup - [ ] 08 Static Type Checking - [ ] 09 Testing From 4689256d6cb465755c9018c552bb39e60f51667b Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:17:23 -0600 Subject: [PATCH 03/14] Proofread ch 07-09: fix stale post-split references - 07 Initialization and Cleanup: "you saw __init__() do that above" now links to the Classes chapter (Classes split out ahead of this one). - 08 Static Type Checking: "functions earlier in this chapter" -> "in the earlier chapters"; "so far this chapter has leaned on that freedom" -> "the book so far ...". This is its own chapter now, not the tail of one. - 09 Testing: read clean, no changes. Co-Authored-By: Claude Opus 4.8 --- Markdown/07_Initialization_and_Cleanup.md | 2 +- Markdown/08_Static_Type_Checking.md | 4 ++-- PROOFREADING_PROGRESS.md | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Markdown/07_Initialization_and_Cleanup.md b/Markdown/07_Initialization_and_Cleanup.md index 40d6268d..03e1d194 100644 --- a/Markdown/07_Initialization_and_Cleanup.md +++ b/Markdown/07_Initialization_and_Cleanup.md @@ -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. diff --git a/Markdown/08_Static_Type_Checking.md b/Markdown/08_Static_Type_Checking.md index a761fcbb..4ed8894e 100644 --- a/Markdown/08_Static_Type_Checking.md +++ b/Markdown/08_Static_Type_Checking.md @@ -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 diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index dac16794..500cf42c 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 2 done (chapters 04-06), committed on branch +Last updated: iteration 3 done (chapters 07-09), committed on branch `proofread/prose-pass`. -Next action: proofread chapters 07-09. +Next action: proofread chapters 10-12. ## Policy @@ -34,9 +34,9 @@ Next action: proofread chapters 07-09. - [x] 04 Functions - [x] 05 Modules and Packages - [x] 06 Classes -- [ ] 07 Initialization and Cleanup -- [ ] 08 Static Type Checking -- [ ] 09 Testing +- [x] 07 Initialization and Cleanup +- [x] 08 Static Type Checking +- [x] 09 Testing - [ ] 10 Data Classes as Types - [ ] 11 Functional Error Handling - [ ] 12 Decorators From d2f9a206d229f4b3d27f344895836af38a40e7c1 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:20:53 -0600 Subject: [PATCH 04/14] Proofread ch 10-12: clean, no changes Data Classes as Types, Functional Error Handling, and Decorators are recent, polished chapters. No spelling, grammar, or clarity issues found. Checkpoint only. Co-Authored-By: Claude Opus 4.8 --- PROOFREADING_PROGRESS.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index 500cf42c..9be6fd2f 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 3 done (chapters 07-09), committed on branch -`proofread/prose-pass`. -Next action: proofread chapters 10-12. +Last updated: iteration 4 done (chapters 10-12, all clean, no changes), +committed on branch `proofread/prose-pass`. +Next action: proofread chapters 13-15. ## Policy @@ -37,9 +37,9 @@ Next action: proofread chapters 10-12. - [x] 07 Initialization and Cleanup - [x] 08 Static Type Checking - [x] 09 Testing -- [ ] 10 Data Classes as Types -- [ ] 11 Functional Error Handling -- [ ] 12 Decorators +- [x] 10 Data Classes as Types +- [x] 11 Functional Error Handling +- [x] 12 Decorators - [ ] 13 Comprehensions - [ ] 14 Metaprogramming - [ ] 15 Rethinking Objects From 0a8d0fe1e225c8ccfaf91b50f3c1502840c9fb8c Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:26:50 -0600 Subject: [PATCH 05/14] Proofread ch 13-15: grammar fixes in Comprehensions 13 Comprehensions (older contributed content) had several clear errors, now fixed: "built in" -> "built-in"; "list so, it is" -> "list, so it is"; "Would be more efficient" -> "It would be more efficient"; a comma splice and missing article in the Set Comprehensions intro; "longer then" -> "longer than"; "capitalised," -> "capitalized;"; a run-on plus missing period in the Dictionary Comprehensions intro. 14 Metaprogramming and 15 Rethinking Objects: read clean, no changes. Co-Authored-By: Claude Opus 4.8 --- Markdown/13_Comprehensions.md | 14 +++++++------- PROOFREADING_PROGRESS.md | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Markdown/13_Comprehensions.md b/Markdown/13_Comprehensions.md index 52852cf7..a3b68437 100644 --- a/Markdown/13_Comprehensions.md +++ b/Markdown/13_Comprehensions.md @@ -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: @@ -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 @@ -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: @@ -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: @@ -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: diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index 9be6fd2f..e885b205 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 4 done (chapters 10-12, all clean, no changes), -committed on branch `proofread/prose-pass`. -Next action: proofread chapters 13-15. +Last updated: iteration 5 done (chapters 13-15), committed on branch +`proofread/prose-pass`. +Next action: proofread chapters 16-18. ## Policy @@ -40,9 +40,9 @@ Next action: proofread chapters 13-15. - [x] 10 Data Classes as Types - [x] 11 Functional Error Handling - [x] 12 Decorators -- [ ] 13 Comprehensions -- [ ] 14 Metaprogramming -- [ ] 15 Rethinking Objects +- [x] 13 Comprehensions +- [x] 14 Metaprogramming +- [x] 15 Rethinking Objects - [ ] 16 The Pattern Concept - [ ] 17 Messenger - [ ] 18 Singleton From 7ac144e90bed575c3527cbbd258e9e2121ab71e0 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:30:40 -0600 Subject: [PATCH 06/14] Proofread ch 16-18: grammar fixes in The Pattern Concept 16 The Pattern Concept (older discursive content): "class of similar problem" -> "problems"; "for awhile" -> "for a while"; "ie" -> "i.e.,". 17 Messenger and 18 Singleton: read clean (both recently rewritten). Co-Authored-By: Claude Opus 4.8 --- Markdown/16_The_Pattern_Concept.md | 6 +++--- PROOFREADING_PROGRESS.md | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Markdown/16_The_Pattern_Concept.md b/Markdown/16_The_Pattern_Concept.md index 4e82f8ce..56dec1ea 100644 --- a/Markdown/16_The_Pattern_Concept.md +++ b/Markdown/16_The_Pattern_Concept.md @@ -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. @@ -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 @@ -249,7 +249,7 @@ your proposed design, to apply tests for quality. - *Reflexivity* (my suggested term). 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 diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index e885b205..40b3aa76 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 5 done (chapters 13-15), committed on branch +Last updated: iteration 6 done (chapters 16-18), committed on branch `proofread/prose-pass`. -Next action: proofread chapters 16-18. +Next action: proofread chapters 19-21. ## Policy @@ -43,9 +43,9 @@ Next action: proofread chapters 16-18. - [x] 13 Comprehensions - [x] 14 Metaprogramming - [x] 15 Rethinking Objects -- [ ] 16 The Pattern Concept -- [ ] 17 Messenger -- [ ] 18 Singleton +- [x] 16 The Pattern Concept +- [x] 17 Messenger +- [x] 18 Singleton - [ ] 19 Application Frameworks - [ ] 20 Fronting for an Implementation - [ ] 21 State Machines From db8810c71867b31d54636e966bdd1250dc878080 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:35:40 -0600 Subject: [PATCH 07/14] Proofread ch 19-21: fixes + 2 findings - 20 Fronting: "For example, or to keep track" -> "For example, to keep track". - 21 State Machines: "copy-on write" -> "copy-on-write". - 19 Application Frameworks: read clean. - Logged 2 findings in ch 21: the StateT paragraph describes a Java Map/null/ 2-D array that does not match the Python dict/None code; and exercises 6/7/12 use Java vocabulary (HashMap, String, nextState(), hasNext()/false) and a missing transition_table.py. Co-Authored-By: Claude Opus 4.8 --- Markdown/20_Fronting_for_an_Implementation.md | 2 +- Markdown/21_State_Machines.md | 2 +- PROOFREADING_FINDINGS.md | 22 +++++++++++++++++++ PROOFREADING_PROGRESS.md | 10 ++++----- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Markdown/20_Fronting_for_an_Implementation.md b/Markdown/20_Fronting_for_an_Implementation.md index 249a4672..15aa5ecb 100644 --- a/Markdown/20_Fronting_for_an_Implementation.md +++ b/Markdown/20_Fronting_for_an_Implementation.md @@ -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 diff --git a/Markdown/21_State_Machines.md b/Markdown/21_State_Machines.md index facefeb1..795c5c41 100644 --- a/Markdown/21_State_Machines.md +++ b/Markdown/21_State_Machines.md @@ -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 diff --git a/PROOFREADING_FINDINGS.md b/PROOFREADING_FINDINGS.md index 455f450d..34f67e24 100644 --- a/PROOFREADING_FINDINGS.md +++ b/PROOFREADING_FINDINGS.md @@ -64,3 +64,25 @@ Format per entry: > redundant here. Suggest trimming to the one point inheritance needs: you > import the base class before subclassing it (as `simple2.py` imports > `Simple`). Flagging rather than cutting, since it is a sizable removal. + +--- + +> **21_State_Machines.md:226-231** (prose does not match the code) +> The paragraph introducing `StateT` says it "adds a `Map` and a method to +> initialize the map from a two-dimensional array," and that the `next()` +> methods "test for a `null Map` ... and initialize it if it's `null`." The +> Python code has no `Map`, no `null`, and no two-dimensional array: it uses a +> `dict` named `transitions`, tests `if not self.transitions`, and each subclass +> builds its dict inline. This is leftover Java-translation prose. Suggest +> rewriting to: a dict of transitions, lazily initialized on first `next()` +> when it is still `None`. + +--- + +> **21_State_Machines.md exercises 6, 7, 12** (Java leftovers) +> The exercises use Java vocabulary and mechanics: ex 7 says "Use a `HashMap`", +> "the key is a `String`", "override a method `nextState()`", and ex 12 ends +> with "before `hasNext()` returns `false`". Ex 6 refers to a `transition_table +> .py` that does not exist in the chapter. Suggest Pythonizing: `dict`, `str`, +> `next_state()`/snake_case, `False`, and pointing ex 6 at the real +> `tabledriven/` files (or dropping it). diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index 40b3aa76..ba8e623c 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 6 done (chapters 16-18), committed on branch +Last updated: iteration 7 done (chapters 19-21), committed on branch `proofread/prose-pass`. -Next action: proofread chapters 19-21. +Next action: proofread chapters 22-24. ## Policy @@ -46,9 +46,9 @@ Next action: proofread chapters 19-21. - [x] 16 The Pattern Concept - [x] 17 Messenger - [x] 18 Singleton -- [ ] 19 Application Frameworks -- [ ] 20 Fronting for an Implementation -- [ ] 21 State Machines +- [x] 19 Application Frameworks +- [x] 20 Fronting for an Implementation +- [x] 21 State Machines - [ ] 22 Iterators - [ ] 23 Factory - [ ] 24 Function Objects From 2d8330c190d1fac9553a3973c7d75fdc3405b2a8 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:39:32 -0600 Subject: [PATCH 08/14] Proofread ch 22-24: two Java-ism/grammar fixes in Factory 23 Factory: "it happens to be a `String`" -> "a string" (Java capitalization); a mid-sentence capital "Is only executed" -> "is only executed". 22 Iterators and 24 Function Objects: read clean (both recently rewritten). Co-Authored-By: Claude Opus 4.8 --- Markdown/23_Factory.md | 4 ++-- PROOFREADING_PROGRESS.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Markdown/23_Factory.md b/Markdown/23_Factory.md index 22fd4c3a..2887e614 100644 --- a/Markdown/23_Factory.md +++ b/Markdown/23_Factory.md @@ -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 @@ -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 diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index ba8e623c..614b2a98 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 7 done (chapters 19-21), committed on branch +Last updated: iteration 8 done (chapters 22-24), committed on branch `proofread/prose-pass`. -Next action: proofread chapters 22-24. +Next action: proofread chapters 25-27. ## Policy @@ -49,9 +49,9 @@ Next action: proofread chapters 22-24. - [x] 19 Application Frameworks - [x] 20 Fronting for an Implementation - [x] 21 State Machines -- [ ] 22 Iterators -- [ ] 23 Factory -- [ ] 24 Function Objects +- [x] 22 Iterators +- [x] 23 Factory +- [x] 24 Function Objects - [ ] 25 Changing the Interface - [ ] 26 Observer - [ ] 27 Multiple Dispatching From 30d45ea4fa532707313313ca735879395502f423 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:44:37 -0600 Subject: [PATCH 09/14] Proofread ch 25-27: grammar fixes + 1 finding - 25 Changing the Interface: "as singleton abstract factory" -> "as a singleton abstract factory". - 26 Observer: mid-sentence "To surround your method" -> "to surround"; subject- verb fix "A grid of boxes each start" -> "A grid of boxes, each starting". - 27 Multiple Dispatching: untangle "..., so how can you get them" -> "..., how can you get them". - Logged 1 finding: Observer's opening paragraph is a sentence fragment with no main verb; proposed a rewrite. Co-Authored-By: Claude Opus 4.8 --- Markdown/25_Changing_the_Interface.md | 2 +- Markdown/26_Observer.md | 6 +++--- Markdown/27_Multiple_Dispatching.md | 2 +- PROOFREADING_FINDINGS.md | 14 ++++++++++++++ PROOFREADING_PROGRESS.md | 10 +++++----- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Markdown/25_Changing_the_Interface.md b/Markdown/25_Changing_the_Interface.md index 21856f82..a4464632 100644 --- a/Markdown/25_Changing_the_Interface.md +++ b/Markdown/25_Changing_the_Interface.md @@ -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: diff --git a/Markdown/26_Observer.md b/Markdown/26_Observer.md index 45871213..0ab72162 100644 --- a/Markdown/26_Observer.md +++ b/Markdown/26_Observer.md @@ -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 @@ -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. diff --git a/Markdown/27_Multiple_Dispatching.md b/Markdown/27_Multiple_Dispatching.md index 53a87aa4..5baf8296 100644 --- a/Markdown/27_Multiple_Dispatching.md +++ b/Markdown/27_Multiple_Dispatching.md @@ -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 diff --git a/PROOFREADING_FINDINGS.md b/PROOFREADING_FINDINGS.md index 34f67e24..de1074c9 100644 --- a/PROOFREADING_FINDINGS.md +++ b/PROOFREADING_FINDINGS.md @@ -86,3 +86,17 @@ Format per entry: > .py` that does not exist in the chapter. Suggest Pythonizing: `dict`, `str`, > `next_state()`/snake_case, `False`, and pointing ex 6 at the real > `tabledriven/` files (or dropping it). + +--- + +> **26_Observer.md:5-12** (broken opening paragraph) +> The chapter opens with a sentence fragment: "*Observer*, and a category of +> callbacks called 'multiple dispatching (not in *Design Patterns*)' including +> the *Visitor* from *Design Patterns*." There is no main verb, and the next +> sentence's "this contains a hook point" has no clear referent. Line 10 also +> has an awkward possessive, "based on other object's change of state". Suggest +> a rewrite, e.g.: "The *Observer* pattern is a kind of callback: an object +> registers interest in another object and is notified when that object's state +> changes. It is the most dynamic of the callback patterns. (A related family, +> multiple dispatching, includes the *Visitor* pattern from *Design Patterns*; +> see the Multiple Dispatching and Visitor chapters.)" diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index 614b2a98..e1a4f1e3 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,9 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 8 done (chapters 22-24), committed on branch +Last updated: iteration 9 done (chapters 25-27), committed on branch `proofread/prose-pass`. -Next action: proofread chapters 25-27. +Next action: proofread chapters 28-30 (final batch). ## Policy @@ -52,9 +52,9 @@ Next action: proofread chapters 25-27. - [x] 22 Iterators - [x] 23 Factory - [x] 24 Function Objects -- [ ] 25 Changing the Interface -- [ ] 26 Observer -- [ ] 27 Multiple Dispatching +- [x] 25 Changing the Interface +- [x] 26 Observer +- [x] 27 Multiple Dispatching - [ ] 28 Visitor - [ ] 29 Pattern Refactoring - [ ] 30 Simulation From b9f53d9c278d46e61fe39d35ad9e1030c59813d3 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 16:48:40 -0600 Subject: [PATCH 10/14] Proofread ch 28-30: final batch, pass complete 28 Visitor, 29 Pattern Refactoring, 30 Simulation: prose reads clean (29 and 30 are recent, polished chapters). Logged 1 finding: Visitor exercises 2-3 are unconverted Java (Map, getClass(), cast expressions). All 30 chapters proofread. Mechanical fixes were applied per batch; judgment calls are collected in PROOFREADING_FINDINGS.md for review. Co-Authored-By: Claude Opus 4.8 --- PROOFREADING_FINDINGS.md | 11 +++++++++++ PROOFREADING_PROGRESS.md | 17 +++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/PROOFREADING_FINDINGS.md b/PROOFREADING_FINDINGS.md index de1074c9..c2c9b97a 100644 --- a/PROOFREADING_FINDINGS.md +++ b/PROOFREADING_FINDINGS.md @@ -100,3 +100,14 @@ Format per entry: > changes. It is the most dynamic of the callback patterns. (A related family, > multiple dispatching, includes the *Visitor* pattern from *Design Patterns*; > see the Multiple Dispatching and Visitor chapters.)" + +--- + +> **28_Visitor.md exercises 2-3** (unconverted Java) +> Exercise 2 uses `getWeapon()` and "member function"; exercise 3 contains +> literal Java: "create a `Map` of `Map`s", `o1.getClass()`, and the cast +> expression `((Map)map.get(o1.getClass())).get(o2.getClass())`. Suggest +> Pythonizing to a `dict` of `dict`s keyed by `type(o1)`/`type(o2)`, +> `type(...)` instead of `getClass()`, snake_case method names, and "method" +> instead of "member function". (Same class of issue as the State Machines +> exercises.) diff --git a/PROOFREADING_PROGRESS.md b/PROOFREADING_PROGRESS.md index e1a4f1e3..2120a34a 100644 --- a/PROOFREADING_PROGRESS.md +++ b/PROOFREADING_PROGRESS.md @@ -4,9 +4,14 @@ Checkpoint for the prose proofreading pass. On restart, read this first, find the first unchecked chapter, and continue from there. Update the checkboxes and the "Last updated" line before ending each iteration. -Last updated: iteration 9 done (chapters 25-27), committed on branch -`proofread/prose-pass`. -Next action: proofread chapters 28-30 (final batch). +Last updated: ALL 30 CHAPTERS PROOFREAD. Pass complete, committed on branch +`proofread/prose-pass`. The loop has stopped. + +Mechanical fixes (spelling, grammar, em-dashes, stale post-split references, +Java-isms) were applied and committed per batch. Judgment calls are in +PROOFREADING_FINDINGS.md for the user to review and approve. Remaining (human): +merge the branch; act on the findings; optionally delete the two tracking +files. ## Policy @@ -55,9 +60,9 @@ Next action: proofread chapters 28-30 (final batch). - [x] 25 Changing the Interface - [x] 26 Observer - [x] 27 Multiple Dispatching -- [ ] 28 Visitor -- [ ] 29 Pattern Refactoring -- [ ] 30 Simulation +- [x] 28 Visitor +- [x] 29 Pattern Refactoring +- [x] 30 Simulation When all are checked, stop the loop (no further ScheduleWakeup). The user reviews PROOFREADING_FINDINGS.md and decides which rewrites to apply. From cc10c7c37116e45004db7057e970a831eb2be0d2 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 18:25:26 -0600 Subject: [PATCH 11/14] edits --- Markdown/12_Decorators.md | 4 +--- Markdown/16_The_Pattern_Concept.md | 20 ++++++-------------- Markdown/19_Application_Frameworks.md | 2 +- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/Markdown/12_Decorators.md b/Markdown/12_Decorators.md index b757a0f1..6d201db3 100644 --- a/Markdown/12_Decorators.md +++ b/Markdown/12_Decorators.md @@ -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) @@ -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 diff --git a/Markdown/16_The_Pattern_Concept.md b/Markdown/16_The_Pattern_Concept.md index 56dec1ea..8f54686a 100644 --- a/Markdown/16_The_Pattern_Concept.md +++ b/Markdown/16_The_Pattern_Concept.md @@ -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** @@ -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. @@ -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. @@ -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, 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 diff --git a/Markdown/19_Application_Frameworks.md b/Markdown/19_Application_Frameworks.md index ce592b11..ee48a82a 100644 --- a/Markdown/19_Application_Frameworks.md +++ b/Markdown/19_Application_Frameworks.md @@ -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 From 134069029e2efba36223e38d1d77ffee35ccac34 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 18:33:19 -0600 Subject: [PATCH 12/14] Update NOTES.md --- NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NOTES.md b/NOTES.md index 26d7d6fa..f437b490 100644 --- a/NOTES.md +++ b/NOTES.md @@ -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 From 8d7674544cc7c5b4976b0aad68d38c3a15c7cb66 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 18:35:59 -0600 Subject: [PATCH 13/14] Apply terminology findings: dynamic typing (ch04), duck typing (ch06) - 04 Functions: "Python is a *structurally-typed* language" -> "Python is dynamically typed" (structural typing is the Protocol concept used elsewhere; this is plain dynamic typing). - 06 Classes: "demonstrates weak typing" -> "duck typing"; "to provide weak typing in a strongly-typed language" -> "duck typing in a statically-typed language". Python is strongly typed, just dynamic; what f() shows is duck typing, and this no longer contradicts the chapter's own "dynamically typed". Marked both findings APPLIED in PROOFREADING_FINDINGS.md. Co-Authored-By: Claude Opus 4.8 --- Markdown/04_Functions.md | 4 ++-- Markdown/06_Classes.md | 4 ++-- PROOFREADING_FINDINGS.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Markdown/04_Functions.md b/Markdown/04_Functions.md index 3d190d65..2f1b8a45 100644 --- a/Markdown/04_Functions.md +++ b/Markdown/04_Functions.md @@ -20,8 +20,8 @@ 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, +argument types or return types. Python is dynamically typed, which means it +puts the minimum possible requirements on typing. For example, you could pass and return different types from the same function: ```python diff --git a/Markdown/06_Classes.md b/Markdown/06_Classes.md index 008d1ac2..3d231a39 100644 --- a/Markdown/06_Classes.md +++ b/Markdown/06_Classes.md @@ -136,13 +136,13 @@ 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. diff --git a/PROOFREADING_FINDINGS.md b/PROOFREADING_FINDINGS.md index c2c9b97a..87859651 100644 --- a/PROOFREADING_FINDINGS.md +++ b/PROOFREADING_FINDINGS.md @@ -25,7 +25,7 @@ Format per entry: --- -> **04_Functions.md:23** (conceptual) +> **04_Functions.md:23** (conceptual) — APPLIED > Original: "Python is a *structurally-typed* language, which means it puts the > minimum possible requirements on typing." > Proposed: "Python is *dynamically typed*, so it puts the minimum possible @@ -45,7 +45,7 @@ Format per entry: --- -> **06_Classes.md:139 and :145** (terminology) +> **06_Classes.md:139 and :145** (terminology) — APPLIED > Original: "demonstrates weak typing" ... "to provide weak typing in a > strongly-typed language." > Proposed: "demonstrates duck typing" ... "to provide duck typing in a From 2b600fa4f647ee296ca2697935d67f7e9ad3f55c Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Tue, 16 Jun 2026 18:51:19 -0600 Subject: [PATCH 14/14] Update 04_Functions.md --- Markdown/04_Functions.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Markdown/04_Functions.md b/Markdown/04_Functions.md index 2f1b8a45..3acb1912 100644 --- a/Markdown/04_Functions.md +++ b/Markdown/04_Functions.md @@ -21,8 +21,8 @@ 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 dynamically typed, which means it -puts the minimum possible requirements on typing. For example, -you could pass and return different types from the same function: +enforces type constraints at runtime. For example, +different types can be both passed to and returned from the same function: ```python # different_returns.py @@ -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