diff --git a/advanced-classes.html b/advanced-classes.html index 5cf84e4..fd2bb4e 100644 --- a/advanced-classes.html +++ b/advanced-classes.html @@ -98,6 +98,8 @@ class OrderedDict(dict, collections.MutableMapping): return all(p==q for p, q in itertools.zip_longest(self.items(), other.items())) return dict.__eq__(self, other) +

⁂ +

Implementing Fractions

⁂ +

Finding all occurrences of a pattern

The first thing this alphametics solver does is find all the letters (A–Z) in the puzzle. @@ -98,6 +100,8 @@ if __name__ == '__main__':

  • Here the regular expression pattern matches sequences of letters. Again, the return value is a list, and each item in the list is a string that matched the regular expression pattern. +

    ⁂ +

    Finding the unique items in a sequence

    Set comprehensions make it trivial to find the unique items in a sequence. [FIXME-not sure if I’m going to cover set comprehensions in an earlier chapter; if not, this is certainly an abrupt and inadequate introduction to the topic.] @@ -127,6 +131,8 @@ if __name__ == '__main__':

    This list is later used to assign digits to characters as the solver iterates through the possible solutions. +

    ⁂ +

    Making assertions

    Like many programming languages, Python has an assert statement. Here’s how it works. @@ -155,6 +161,8 @@ AssertionError

    The alphametics solver uses this exact assert statement to bail out early if the puzzle contains more than ten unique letters. Since each letter is assigned a unique digit, and there are only ten digits, a puzzle with more than ten unique letters is unsolvable. +

    ⁂ +

    Generator expressions

    A generator expression is like a generator function without the function. @@ -185,6 +193,8 @@ AssertionError gen = ord_map(unique_characters) +

    ⁂ +

    Calculating Permutations… The Lazy Way!

    First of all, what the heck are permutations? Permutations are a mathematical concept. (There are actually several definitions, depending on what kind of math you’re doing. Here I’m talking about combinatorics, but if that doesn’t mean anything to you, don’t worry about it. As always, Wikipedia is your friend.) @@ -249,6 +259,8 @@ StopIteration

  • Since the permutations() function always returns an iterator, an easy way to debug permutations is to pass that iterator to the built-in list() function to see all the permutations immediately. +

    ⁂ +

    Other Fun Stuff in the itertools Module

     >>> import itertools
    @@ -372,6 +384,8 @@ for guess in itertools.permutations(digits, len(characters)):
     
     

    But what is this translate() method? Ah, now you’re getting to the really fun part. +

    ⁂ +

    A New Kind Of String Manipulation

    Python strings have many methods. You learned about some of those methods in the Strings chapter: lower(), count(), and format(). Now I want to introduce you to a powerful but little-known string manipulation technique: the translate() method. @@ -411,6 +425,8 @@ for guess in itertools.permutations(digits, len(characters)):

    That’s pretty impressive. But what can you do with a string that happens to be a valid Python expression? +

    ⁂ +

    Evaluating Arbitrary Strings As Python Expressions

    This is the final piece of the puzzle (or rather, the final piece of the puzzle solver). After all that fancy string manipulation, we’re left with a string like '9567 + 1085 == 10652'. But that’s a string, and what good is a string? Enter eval(), the universal Python evaluation tool. @@ -542,6 +558,8 @@ NameError: name '__import__' is not defined

    So, in the end, it is possible to safely evaluate untrusted Python expressions. Passing {"__builtins__": None} as the second parameter to the eval() function is non-intuitive (and not the default behavior), but it does work. If you understand why it works, you’re less likely to use eval() incorrectly, in a way that works with trusted input but has potentially devastating consequences with untrusted input. +

    ⁂ +

    Putting It All Together

    To recap: this program solves alphametic puzzles by brute force, i.e. through an exhaustive search of all possible solutions. To do this, it… @@ -559,6 +577,8 @@ NameError: name '__import__' is not defined

    …in just 14 lines of code. +

    ⁂ +

    Further Reading