I am currently reading the book Fluent Python - Luciano Ramalho (a great book IMO).
In the chapter about decorators and closures, there is a following piece of code:
def make_averager():
series = []
def averager(value):
series.append(value)
total = sum(series)
return total/len(series)
return averager
avg = make_averager()
So in this case, series
is a free variable, and I can verify this by printing
>>> avg.__code__.co_varnames
('new_value', 'total')
>>> avg.__code__.co_freevars
('series',)
But when I tried refactoring the make_averager()
:
def make_averager():
series = []
total = 0
count = 0
def averager(value):
total += value
count += 1
return total/count
return averager
avg = make_averager()
either series
, total
or sum
is considered a free_variable. Instead, total
and sum
are now local variables (?) since avg.__code__.co_varnames
returns ('value', 'total', 'count')
and avg.__code__.co_freevars
returns ()
.
So now series
is now no longer a free-variable in the scope of averager
, unless I add
series.append(value)
inside averager(value)
. This is understandable since I don't call series
at all inside averager(value)
, but I couldn't understand what's happening with those 2 variables.
Why are total
and count
not considered as free-variables, and how do I assign them as free-variables?
def averager(value):
nonlocal total
nonlocal count
total += value
count += 1
return total/count
Without nonlocal, total += value
assigns to total
which by default creates a local variable. Since total
is in the local scope of the function averager
, it is no longer a free variable.