Closures
A closure is a function that references variables from outside its own function body. The function definition and its environment are bundled together into a single entity.
Put simply, a closure is just a function that keeps track of some values from the place where it was defined, no matter where it is executed later on.
Example
The concatter()
function returns a function called doc_builder
(yay higher-order functions!) that has a reference to an enclosed doc
value
def concatter():
doc = ""
def doc_builder(word):
# "nonlocal" tells Python to use the 'doc'
# variable from the enclosing scope
nonlocal doc
doc += word + " "
return doc
return doc_builder
# save the returned 'doc_builder' function
# to the new function 'harry_potter_aggregator'
harry_potter_aggregator = concatter()
harry_potter_aggregator("Mr.")
harry_potter_aggregator("and")
harry_potter_aggregator("Mrs.")
harry_potter_aggregator("Dursley")
harry_potter_aggregator("of")
harry_potter_aggregator("number")
harry_potter_aggregator("four,")
harry_potter_aggregator("Privet")
print(harry_potter_aggregator("Drive"))
# Mr. and Mrs. Dursley of number four, Privet Drive
When concatter()
is called, it creates a new "stateful" function that remembers the value of its internal doc
variable. Each successive call to harry_potter_aggregator
appends to that same doc
.
nonlocal
Python has a keyword called nonlocal that's required to modify a variable from an enclosing scope. Most programming languages don't require this keyword, but Python does.
nonlocal_stmt ::= "nonlocal" ("," )*
When the definition of a function or class is nested (enclosed) within the definitions of other functions, its nonlocal scopes are the local scopes of the enclosing functions. The nonlocal
statement causes the listed identifiers to refer to names previously bound in nonlocal scopes. It allows encapsulated code to rebind such nonlocal identifiers. If a name is bound in more than one nonlocal scope, the nearest binding is used. If a name is not bound in any nonlocal scope, or if there is no nonlocal scope, a SyntaxError
is raised.
The nonlocal
statement applies to the entire scope of a function or class body. A SyntaxError
is raised if a variable is used or assigned to prior to its nonlocal declaration in the scope.
Assignment
Doc2Doc keeps track of how many words are in a collection of documents.
Complete the word_count_aggregator
function. It should return a function that calculates the number of words in its input (doc
, a string). It should then add that number to an enclosed count
value and return the new count
. In other words, it keeps a running total of the count
variable within a closure.
Solution
def word_count_aggregator():
count = 0
def calculator(doc):
nonlocal count
count += len(doc.split())
return count
return calculator
How The Code Works
count = 0
→ Initializes a variable to store the running total of words.calculator(doc)
→ Defines an inner function that:Uses
nonlocal count
to modify the outer variable.Splits the input string (
doc
) into words and counts them.Adds the count to the running total.
Returns the updated count.
Returns
calculator
→ The function returned maintains thecount
variable across multiple calls.
word_counter = word_count_aggregator()
print(word_counter("Hello world")) # Output: 2
print(word_counter("This is a test")) # Output: 6
print(word_counter("Adding more words")) # Output: 9
Last updated