0

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?

petezurich
  • 9,280
  • 9
  • 43
  • 57
ViM
  • 3
  • 1

1 Answers1

1

nonlocal total, count

def averager(value):
    nonlocal total
    nonlocal count
    total += value
    count += 1
    return total/count

Why does nonlocal make them free variables?

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.

Kelly Bundy
  • 23,480
  • 7
  • 29
  • 65
SargeATM
  • 2,483
  • 14
  • 24
  • Thank you for this simple solution. But could you explain why `series` is considered a `nonlocal` in the first approach, while `total` and `sum` aren't in the second? – ViM Aug 24 '22 at 19:55
  • You never assign to the `series` variable.(e.g. `series = []`) `series.append` translates to find object held by `series` variable. Is `series` in local scope? No. try outer scope, yes. Now ask series object for method `append` so that I can call it. – SargeATM Aug 24 '22 at 19:58