diff --git a/advanced-iterators.html b/advanced-iterators.html index 472ae72..cd585dd 100755 --- a/advanced-iterators.html +++ b/advanced-iterators.html @@ -38,7 +38,7 @@ S = 6 T = 2 E = 4 -

Puzzles like this are called cryptarithms or alphametics. The letters spell out actual words, but if you replace each letter with a digit from 0–9, it also “spells” an arithmetic equation. The trick is to figure out which letter maps to each digit. All the occurrences of each letter must map to the same digit, no digit can be repeated, and no “word” can start with the digit 0. +

Puzzles like this are called cryptarithms or alphametics. The letters spell out actual words, but if you replace each letter with a digit from 0–9, it also “spells” an arithmetic equation. The trick is to figure out which letter maps to each digit. All the occurrences of each letter must map to the same digit, no digit can be repeated, and no “word” can start with the digit 0.

The most well-known alphametic puzzle is SEND + MORE = MONEY. diff --git a/comprehensions.html b/comprehensions.html index b0a7c07..2d3b11e 100644 --- a/comprehensions.html +++ b/comprehensions.html @@ -334,7 +334,7 @@ body{counter-reset:h1 3} {32, 1, 2, 4, 8, 64, 128, 256, 16, 512}

    -
  1. Set comprehensions can take a set as input. This set comprehension calculates the squares of the set of numbers from 0 to 9. +
  2. Set comprehensions can take a set as input. This set comprehension calculates the squares of the set of numbers from 0 to 9.
  3. Like list comprehensions and dictionary comprehensions, set comprehensions can contain an if clause to filter each item before returning it in the result set.
  4. Set comprehensions do not need to take a set as input; they can take any sequence.
diff --git a/generators.html b/generators.html index e2cedde..829a94a 100755 --- a/generators.html +++ b/generators.html @@ -349,7 +349,7 @@ def plural(noun, rules_filename='plural5-rules.txt'): yield a a, b = b, a + b
    -
  1. The Fibonacci sequence is a sequence of numbers where each number is the sum of the two numbers before it. It starts with 0 and 1, goes up slowly at first, then more and more rapidly. To start the sequence, you need two variables: a starts at 0, and b starts at 1. +
  2. The Fibonacci sequence is a sequence of numbers where each number is the sum of the two numbers before it. It starts with 0 and 1, goes up slowly at first, then more and more rapidly. To start the sequence, you need two variables: a starts at 0, and b starts at 1.
  3. a is the current number in the sequence, so yield it.
  4. b is the next number in the sequence, so assign that to a, but also calculate the next value (a + b) and assign that to b for later use. Note that this happens in parallel; if a is 3 and b is 5, then a, b = b, a + b will set a to 5 (the previous value of b) and b to 8 (the sum of the previous values of a and b).
diff --git a/native-datatypes.html b/native-datatypes.html index 00afa04..9d726b2 100755 --- a/native-datatypes.html +++ b/native-datatypes.html @@ -42,7 +42,7 @@ body{counter-reset:h1 2}

For example, take this snippet from humansize.py:

if size < 0:
     raise ValueError('number must be non-negative')
-

size is an integer, 0 is an integer, and < is a numerical operator. The result of the expression size < 0 is always a boolean. You can test this yourself in the Python interactive shell: +

size is an integer, 0 is an integer, and < is a numerical operator. The result of the expression size < 0 is always a boolean. You can test this yourself in the Python interactive shell:

 >>> size = 1
 >>> size < 0
@@ -53,7 +53,7 @@ body{counter-reset:h1 2}
 >>> size = -1
 >>> size < 0
 True
-

Due to some legacy issues left over from Python 2, booleans can be treated as numbers. True is 1; False is 0. +

Due to some legacy issues left over from Python 2, booleans can be treated as numbers. True is 1; False is 0.

 >>> True + True
 2
@@ -107,7 +107,7 @@ ZeroDivisionError: int division or modulo by zero
  • You can explicitly coerce an int to a float by calling the float() function.
  • Unsurprisingly, you can also coerce a float to an int by calling int().
  • The int() function will truncate, not round. -
  • The int() function truncates negative numbers towards 0. It’s a true truncate function, not a a floor function. +
  • The int() function truncates negative numbers towards 0. It’s a true truncate function, not a a floor function.
  • Floating point numbers are accurate to 15 decimal places.
  • Integers can be arbitrarily large. @@ -132,7 +132,7 @@ ZeroDivisionError: int division or modulo by zero
    1. The / operator performs floating point division. It returns a float even if both the numerator and denominator are ints. -
    2. The // operator performs a quirky kind of integer division. When the result is positive, you can think of it as truncating (not rounding) to 0 decimal places, but be careful with that. +
    3. The // operator performs a quirky kind of integer division. When the result is positive, you can think of it as truncating (not rounding) to 0 decimal places, but be careful with that.
    4. When integer-dividing negative numbers, the // operator rounds “up” to the nearest integer. Mathematically speaking, it’s rounding “down” since −6 is less than −5, but it could trip you up if you expecting it to truncate to −5.
    5. The // operator doesn’t always return an integer. If either the numerator or denominator is a float, it will still round to the nearest integer, but the actual return value will be a float.
    6. The ** operator means “raised to the power of.” 112 is 121. @@ -207,8 +207,8 @@ ZeroDivisionError: Fraction(0, 0) no, it's false
      1. Did you know you can define your own functions in the Python interactive shell? Just press ENTER at the end of each line, and ENTER on a blank line to finish. -
      2. In a boolean context, non-zero integers are true; 0 is false. -
      3. Non-zero floating point numbers are true; 0.0 is false. Be careful with this one! If there’s the slightest rounding error (not impossible, as you saw in the previous section) then Python will be testing 0.0000000000001 instead of 0 and will return True. +
      4. In a boolean context, non-zero integers are true; 0 is false. +
      5. Non-zero floating point numbers are true; 0.0 is false. Be careful with this one! If there’s the slightest rounding error (not impossible, as you saw in the previous section) then Python will be testing 0.0000000000001 instead of 0 and will return True.
      6. Fractions can also be used in a boolean context. Fraction(0, n) is false for all values of n. All other fractions are true.

      ⁂ @@ -264,7 +264,7 @@ ZeroDivisionError: Fraction(0, 0)

    7. You can get a part of a list, called a “slice”, by specifying two indices. The return value is a new list containing all the items of the list, in order, starting with the first slice index (in this case a_list[1]), up to but not including the second slice index (in this case a_list[3]).
    8. Slicing works if one or both of the slice indices is negative. If it helps, you can think of it this way: reading the list from left to right, the first slice index specifies the first item you want, and the second slice index specifies the first item you don’t want. The return value is everything in between.
    9. Lists are zero-based, so a_list[0:3] returns the first three items of the list, starting at a_list[0], up to but not including a_list[3]. -
    10. If the left slice index is 0, you can leave it out, and 0 is implied. So a_list[:3] is the same as a_list[0:3], because the starting 0 is implied. +
    11. If the left slice index is 0, you can leave it out, and 0 is implied. So a_list[:3] is the same as a_list[0:3], because the starting 0 is implied.
    12. Similarly, if the right slice index is the length of the list, you can leave it out. So a_list[3:] is the same as a_list[3:5], because this list has five items. There is a pleasing symmetry here. In this five-item list, a_list[:3] returns the first 3 items, and a_list[3:] returns the last two items. In fact, a_list[:n] will always return the first n items, and a_list[n:] will return the rest, regardless of the length of the list.
    13. If both slice indices are left out, all items of the list are included. But this is not the same as the original a_list variable. It is a new list that happens to have all the same items. a_list[:] is shorthand for making a complete copy of a list.
    @@ -340,7 +340,7 @@ ValueError: list.index(x): x not in list
    1. As you might expect, the count() method returns the number of occurrences of a specific value in a list.
    2. If all you want to know is whether a value is in the list or not, the in operator is slightly faster than using the count() method. The in operator always returns True or False; it will not tell you where in the list the value is. -
    3. If you need to know exactly where in the list a value is, call the index() method. By default it will search the entire list, although you can specify a second argument of the (0-based) index to start from, and even a third argument of the (0-based) index to stop searching. +
    4. If you need to know exactly where in the list a value is, call the index() method. By default it will search the entire list, although you can specify a second argument of the (0-based) index to start from, and even a third argument of the (0-based) index to stop searching.
    5. The index() method finds the first occurrence of a value in the list. In this case, 'new' occurs twice in the list, in a_list[2] and a_list[4], but the index() method will return only the index of the first occurrence.
    6. As you might not expect, if the value is not found in the list, the index() method will raise an exception.
    @@ -556,7 +556,7 @@ AttributeError: 'tuple' object has no attribute 'remove' 6
    1. The built-in range() function constructs a sequence of integers. (Technically, the range() function returns an iterator, not a list or a tuple, but you’ll learn about that distinction later.) MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, and SUNDAY are the variables you’re defining. (This example came from the calendar module, a fun little module that prints calendars, like the UNIX program cal. The calendar module defines integer constants for days of the week.) -
    2. Now each variable has its value: MONDAY is 0, TUESDAY is 1, and so forth. +
    3. Now each variable has its value: MONDAY is 0, TUESDAY is 1, and so forth.

    You can also use multi-variable assignment to build functions that return multiple values, simply by returning a tuple of all the values. The caller can treat it as a single tuple, or it can assign the values to individual variables. Many standard Python libraries do this, including the os module, which you'll learn about in the next chapter. @@ -909,7 +909,7 @@ KeyError: 'db.diveintopython3.org'

    None

    -

    None is a special constant in Python. It is a null value. None is not the same as False. None is not 0. None is not an empty string. Comparing None to anything other than None will always return False. +

    None is a special constant in Python. It is a null value. None is not the same as False. None is not 0. None is not an empty string. Comparing None to anything other than None will always return False.

    None is the only null value. It has its own datatype (NoneType). You can assign None to any variable, but you can not create other NoneType objects. All variables whose value is None are equal to each other.

     >>> type(None)
    diff --git a/porting-code-to-python-3-with-2to3.html b/porting-code-to-python-3-with-2to3.html
    index 73c0224..fc78df2 100644
    --- a/porting-code-to-python-3-with-2to3.html
    +++ b/porting-code-to-python-3-with-2to3.html
    @@ -1315,7 +1315,7 @@ except:
     
     

    Common idioms (explicit)

    -

    There were a number of common idioms built up in the Python community. Some, like the while 1: loop, date back to Python 1. (Python didn’t have a true boolean type until version 2.3, so developers used 1 and 0 instead.) Modern Python programmers should train their brains to use modern versions of these idioms instead. +

    There were a number of common idioms built up in the Python community. Some, like the while 1: loop, date back to Python 1. (Python didn’t have a true boolean type until version 2.3, so developers used 1 and 0 instead.) Modern Python programmers should train their brains to use modern versions of these idioms instead.

    The 2to3 script will not fix common idioms by default. To enable this fix, specify -f idioms on the command line when you call 2to3. diff --git a/regular-expressions.html b/regular-expressions.html index 8e8b4ce..b1b69ec 100755 --- a/regular-expressions.html +++ b/regular-expressions.html @@ -311,7 +311,7 @@ body{counter-reset:h1 5} File "<stdin>", line 1, in <module> AttributeError: 'NoneType' object has no attribute 'groups'

      -
    1. Always read regular expressions from left to right. This one matches the beginning of the string, and then (\d{3}). What’s \d{3}? Well, \d means “any numeric digit” (0 through 9). The {3} means “match exactly three numeric digits”; it’s a variation on the {n,m} syntax you saw earlier. Putting it all in parentheses means “match exactly three numeric digits, and then remember them as a group that I can ask for later”. Then match a literal hyphen. Then match another group of exactly three digits. Then another literal hyphen. Then another group of exactly four digits. Then match the end of the string. +
    2. Always read regular expressions from left to right. This one matches the beginning of the string, and then (\d{3}). What’s \d{3}? Well, \d means “any numeric digit” (0 through 9). The {3} means “match exactly three numeric digits”; it’s a variation on the {n,m} syntax you saw earlier. Putting it all in parentheses means “match exactly three numeric digits, and then remember them as a group that I can ask for later”. Then match a literal hyphen. Then match another group of exactly three digits. Then another literal hyphen. Then another group of exactly four digits. Then match the end of the string.
    3. To get access to the groups that the regular expression parser remembered along the way, use the groups() method on the object that the search() method returns. It will return a tuple of however many groups were defined in the regular expression. In this case, you defined three groups, one with three digits, one with three digits, and one with four digits.
    4. This regular expression is not the final answer, because it doesn’t handle a phone number with an extension on the end. For that, you’ll need to expand the regular expression.
    5. And this is why you should never “chain” the search() and groups() methods in production code. If the search() method returns no matches, it returns None, not a regular expression match object. Calling None.groups() raises a perfectly obvious exception: None doesn’t have a groups() method. (Of course, it’s slightly less obvious when you get this exception from deep within your code. Yes, I speak from experience here.) diff --git a/special-method-names.html b/special-method-names.html index 4b6187c..43b9c1b 100644 --- a/special-method-names.html +++ b/special-method-names.html @@ -614,7 +614,7 @@ class FieldStorage: math.floor(x) x.__floor__() -truncate x to nearest integer toward 0 +truncate x to nearest integer toward 0 math.trunc(x) x.__trunc__() PEP 357 @@ -783,15 +783,15 @@ def __exit__(self, *args): hash(x) x.__hash__() -to get an attribute’s value +to get a property’s value x.color type(x).__dict__['color'].__get__(x, type(x)) -to set an attribute’s value +to set a property’s value x.color = 'PapayaWhip' type(x).__dict__['color'].__set__(x, 'PapayaWhip') -to delete an attribute +to delete a property del x.color type(x).__dict__['color'].__del__(x) diff --git a/strings.html b/strings.html index 665c227..d2ec92c 100755 --- a/strings.html +++ b/strings.html @@ -290,7 +290,7 @@ experience of years.
    6. You can get a part of a string, called a “slice”, by specifying two indices. The return value is a new string containing all the characters of the string, in order, starting with the first slice index (in this case a_string[0]), up to but not including the second slice index (in this case a_string[2]).
    7. Like slicing lists, you can use negative indices to slice strings.
    8. Strings are zero-based, so a_string[0:3] returns the first three items of the string, starting at a_string[0], up to but not including a_string[3]. -
    9. If the left slice index is 0, you can leave it out, and 0 is implied. So a_string[:18] is the same as a_string[0:18], because the starting 0 is implied. +
    10. If the left slice index is 0, you can leave it out, and 0 is implied. So a_string[:18] is the same as a_string[0:18], because the starting 0 is implied.
    11. Similarly, if the right slice index is the length of the string, you can leave it out. So a_string[18:] is the same as a_string[18:44], because this string has 44 characters. There is a pleasing symmetry here. In this 44-character string, a_string[:18] returns the first 18 characters, and a_string[18:] returns everything but the first 18 characters. In fact, a_string[:n] will always return the first n characters, and a_string[n:] will return the rest, regardless of the length of the string.
    diff --git a/unit-testing.html b/unit-testing.html index 2ffc112..9a91c05 100755 --- a/unit-testing.html +++ b/unit-testing.html @@ -26,7 +26,7 @@ body{counter-reset:h1 9}
  • There is only one correct way to represent a particular number as a Roman numeral.
  • The converse is also true: if a string of characters is a valid Roman numeral, it represents only one number (that is, it can only be interpreted one way).
  • There is a limited range of numbers that can be expressed as Roman numerals, specifically 1 through 3999. The Romans did have several ways of expressing larger numbers, for instance by having a bar over a numeral to represent that its normal value should be multiplied by 1000. For the purposes of this chapter, let’s stipulate that Roman numerals go from 1 to 3999. -
  • There is no way to represent 0 in Roman numerals. +
  • There is no way to represent 0 in Roman numerals.
  • There is no way to represent negative numbers in Roman numerals.
  • There is no way to represent fractions or non-integer numbers in Roman numerals. @@ -350,7 +350,7 @@ OK

    More Halting, More Fire

    -

    Along with testing numbers that are too large, you need to test numbers that are too small. As we noted in our functional requirements, Roman numerals cannot express 0 or negative numbers. +

    Along with testing numbers that are too large, you need to test numbers that are too small. As we noted in our functional requirements, Roman numerals cannot express 0 or negative numbers.

     >>> import roman2
    @@ -376,7 +376,7 @@ OK
    self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, -1)
    1. The test_too_large() method has not changed since the previous step. I’m including it here to show where the new code fits. -
    2. Here’s a new test: the test_zero() method. Like the test_too_large() method, it tells the assertRaises() method defined in unittest.TestCase to call our to_roman() function with a parameter of 0, and check that it raises the appropriate exception, OutOfRangeError. +
    3. Here’s a new test: the test_zero() method. Like the test_too_large() method, it tells the assertRaises() method defined in unittest.TestCase to call our to_roman() function with a parameter of 0, and check that it raises the appropriate exception, OutOfRangeError.
    4. The test_negative() method is almost identical, except it passes -1 to the to_roman() function. If either of these new tests does not raise an OutOfRangeError (either because the function returns an actual value, or because it raises some other exception), the test is considered failed.
    @@ -558,7 +558,7 @@ OK

    A Pleasing Symmetry

    -

    Converting a string from a Roman numeral to an integer sounds more difficult than converting an integer to a Roman numeral. Certainly there is the issue of validation. It’s easy to check if an integer is greater than 0, but a bit harder to check whether a string is a valid Roman numeral. But we already constructed a regular expression to check for Roman numerals, so that part is done. +

    Converting a string from a Roman numeral to an integer sounds more difficult than converting an integer to a Roman numeral. Certainly there is the issue of validation. It’s easy to check if an integer is greater than 0, but a bit harder to check whether a string is a valid Roman numeral. But we already constructed a regular expression to check for Roman numerals, so that part is done.

    That leaves the problem of converting the string itself. As we’ll see in a minute, thanks to the rich data structure we defined to map individual Roman numerals to integer values, the nitty-gritty of the from_roman() function is as straightforward as the to_roman() function. diff --git a/xml.html b/xml.html index 5ec8fff..c774a44 100755 --- a/xml.html +++ b/xml.html @@ -320,9 +320,9 @@ mark{display:inline} {}

    1. The attrib property is a dictionary of the element’s attributes. The original markup here was <feed xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>. The xml: prefix refers to a built-in namespace that every XML document can use without declaring it. -
    2. The fifth child — [4] in a 0-based list — is the link element. +
    3. The fifth child — [4] in a 0-based list — is the link element.
    4. The link element has three attributes: href, type, and rel. -
    5. The fourth child — [3] in a 0-based list — is the updated element. +
    6. The fourth child — [3] in a 0-based list — is the updated element.
    7. The updated element has no attributes, so its .attrib is just an empty dictionary.
    @@ -386,7 +386,7 @@ mark{display:inline}
    -

    There is a “gotcha” with the find() method that will eventually bite you. In a boolean context, ElementTree element objects will evaluate to False if they contain no children (i.e. if len(element) is 0). This means that if element.find('...') is not testing whether the find() method found a matching element; it’s testing whether that matching element has any child elements! To test whether the find() method returned an element, use if element.find('...') is not None. +

    There is a “gotcha” with the find() method that will eventually bite you. In a boolean context, ElementTree element objects will evaluate to False if they contain no children (i.e. if len(element) is 0). This means that if element.find('...') is not testing whether the find() method found a matching element; it’s testing whether that matching element has any child elements! To test whether the find() method returned an element, use if element.find('...') is not None.

    There is a way to search for descendant elements, i.e. children, grandchildren, and any element at any nesting level.