Generators
We'll cover the following...
Wouldn’t it be grand to have a generic plural()
function that parses the rules file? Get rules, check for a match, apply appropriate transformation, go to next rule. That’s all the plural()
function has to do, and that’s all the plural()
function should do.
def rules(rules_filename):with open(rules_filename, encoding='utf-8') 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, 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))
How the heck does that work? Let’s look at an interactive example first.
def make_counter(x):print('entering make_counter')while True:yield x #①print('incrementing x')x = x + 1counter = make_counter(2) #②print (counter) #③#<generator object at 0x001C9C10>print (next(counter)) #④#entering make_counter#2print (next(counter)) #⑤#incrementing x#3print (next(counter)) #⑥#incrementing x#4
① The presence of the yield
keyword in make_counter
means that this is not a normal function. It is a special kind of function which generates values one at a time. You can think of it as a resumable function. Calling it will return a generator that can be used to generate successive values of x
.
② To create an instance of the make_counter
generator, just call it like any other function. Note that this does not actually execute the function code. You can tell this because the first line of the make_counter()
function calls print()
, but nothing has been printed yet.
③ The make_counter()
function returns a generator object.
④ The next()
function takes a generator object and returns its next value. The first time you call ...