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/Markdown/04_Functions.md b/Markdown/04_Functions.md index 3d190d65..3acb1912 100644 --- a/Markdown/04_Functions.md +++ b/Markdown/04_Functions.md @@ -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 @@ -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 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..3d231a39 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,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. 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/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/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/Markdown/16_The_Pattern_Concept.md b/Markdown/16_The_Pattern_Concept.md index 4e82f8ce..8f54686a 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 @@ -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, 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 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 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/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/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/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 diff --git a/PROOFREADING_FINDINGS.md b/PROOFREADING_FINDINGS.md new file mode 100644 index 00000000..87859651 --- /dev/null +++ b/PROOFREADING_FINDINGS.md @@ -0,0 +1,113 @@ +# 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. + +--- + +> **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 +> 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) — APPLIED +> 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. + +--- + +> **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). + +--- + +> **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.)" + +--- + +> **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 new file mode 100644 index 00000000..2120a34a --- /dev/null +++ b/PROOFREADING_PROGRESS.md @@ -0,0 +1,68 @@ +# 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: 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 + +- 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 +- [x] 04 Functions +- [x] 05 Modules and Packages +- [x] 06 Classes +- [x] 07 Initialization and Cleanup +- [x] 08 Static Type Checking +- [x] 09 Testing +- [x] 10 Data Classes as Types +- [x] 11 Functional Error Handling +- [x] 12 Decorators +- [x] 13 Comprehensions +- [x] 14 Metaprogramming +- [x] 15 Rethinking Objects +- [x] 16 The Pattern Concept +- [x] 17 Messenger +- [x] 18 Singleton +- [x] 19 Application Frameworks +- [x] 20 Fronting for an Implementation +- [x] 21 State Machines +- [x] 22 Iterators +- [x] 23 Factory +- [x] 24 Function Objects +- [x] 25 Changing the Interface +- [x] 26 Observer +- [x] 27 Multiple Dispatching +- [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.