From f67581298af1cd8695ba868e62e7712664c2ac15 Mon Sep 17 00:00:00 2001 From: Mark Pilgrim Date: Thu, 9 Jul 2009 01:42:21 -0400 Subject: [PATCH] fixed numbering, fixed file() typo, take rules file as an argument in plural5.py --- examples/plural5.py | 8 ++++---- generators.html | 17 +++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/plural5.py b/examples/plural5.py index 31e192a..0a552c1 100644 --- a/examples/plural5.py +++ b/examples/plural5.py @@ -14,14 +14,14 @@ def build_match_and_apply_functions(pattern, search, replace): return re.sub(search, replace, word) return [matches_rule, apply_rule] -def rules(): - with open('plural5-rules.txt') as pattern_file: +def rules(rules_filename): + with open(rules_filename) as pattern_file: for line in pattern_file: pattern, search, replace = line.split(None, 3) yield build_match_and_apply_functions(pattern, search, replace) -def plural(noun): - for matches_rule, apply_rule in rules(): +def plural(noun, rules_filename='plural5-rules.txt'): + for matches_rule, apply_rule in rules(rules_filename): if matches_rule(noun): return apply_rule(noun) raise ValueError('no matching rule for {0}'.format(noun)) diff --git a/generators.html b/generators.html index 17ac5c5..56a6e2d 100644 --- a/generators.html +++ b/generators.html @@ -375,20 +375,21 @@ def plural(noun):

Let’s go back to plural5.py and see how this version of the plural() function works. -

def rules():
-    with open('plural5-rules.txt') as pattern_file:
+
def rules(rules_filename):
+    with open(rules_filename) as pattern_file:
         for line in pattern_file:
-            pattern, search, replace = line.split(None, 3)                   
-            yield build_match_and_apply_functions(pattern, search, replace)  
+            pattern, search, replace = line.split(None, 3)                   
+            yield build_match_and_apply_functions(pattern, search, replace)  
 
-def plural(noun):
-    for matches_rule, apply_rule in rules():                                 
+def plural(noun, rules_filename='plural5-rules.txt'):
+    for matches_rule, apply_rule in rules(rules_filename):                   
         if matches_rule(noun):
-            return apply_rule(noun)
+ return apply_rule(noun) + raise ValueError('no matching rule for {0}'.format(noun))
  1. No magic here. Remember that the lines of the rules file have three values separated by whitespace, so you use line.split(None, 3) to get the three “columns” and assign them to three local variables.
  2. And then you yield. What do you yield? Two functions, built dynamically with your old friend, build_match_and_apply_functions(), which is identical to the previous examples. In other words, rules() is a generator that spits out match and apply functions on demand. -
  3. Since rules() is a generator, you can use it directly in a for loop. The first time through the for loop, you will call the rules() function, which will open the pattern file, read the first line, dynamically build a match function and an apply function from the patterns on that line, and yield the dynamically built functions. The second time through the for loop, you will pick up exactly where you left off in rules() (which was in the middle of the for line in file(...) loop). The first thing it will do is read the next line of the file (which is still open), dynamically build another match and apply function based on the patterns on that line in the file, and yield the two functions. +
  4. Since rules() is a generator, you can use it directly in a for loop. The first time through the for loop, you will call the rules() function, which will open the pattern file, read the first line, dynamically build a match function and an apply function from the patterns on that line, and yield the dynamically built functions. The second time through the for loop, you will pick up exactly where you left off in rules() (which was in the middle of the for line in pattern_file loop). The first thing it will do is read the next line of the file (which is still open), dynamically build another match and apply function based on the patterns on that line in the file, and yield the two functions.

What have you gained over stage 4? Startup time. In stage 4, when you imported the plural4 module, it read the entire patterns file and built a list of all the possible rules, before you could even think about calling the plural() function. With generators, you can do everything lazily: you read the first rule and create functions and try them, and if that works you don’t ever read the rest of the file or create any other functions.