[Python-ideas] Persisting private function state between calls (was: "Read Only" namespaces)

Eric Snow ericsnowcurrently at gmail.com
Sat Mar 29 19:39:31 CET 2014


On Sat, Mar 29, 2014 at 9:51 AM, Richard Prosser
<richard.prosser at mail.com> wrote:
> Quite simply, the principle is to allow changes to variables within a
> function body (for example) but not outside of it, rather like the
> Functional Programming paradigm. That of course excludes the use of global
> variables and requires functions to return whatever is needed to the outer
> scope. In my experience, globals are only needed to implement persistent
> (inter-call) states anyway, so assuming that such a feature is available in
> the language I believe that the "Read Only" proposal is viable.

To restate, you want a way to have some variables in your function
body that persist between calls without using global variables.  There
are already several ways to do this, though none is particularly
obvious.

Let's use a simple example using a global variable followed by the
alternative solutions.

current = 0

def adder(x):
    global current
    current += x
    return current

1. Still use a global variable, but make it "private" (just use the
convention of a leading underscore on the name):

_current = 0

def adder(x):
    global _current
    _current += x
    return _current

2. Use the "default argument hack":

def adder(x, _ns={'current': 0}):
    _ns['current'] += x
    return _ns['current']

or

class IntWrapper:
    def __init__(self, value=0):
        self.value = value

def adder(x, _current=IntWrapper()):
    _current.value += x
    return _current.value

3. Use a closure (making use of the "nonlocal" keyword):

def get_adder(start=0):
    current = start  # Done for clarity.
    def adder(x):
        nonlocal current
        current += x
        return current
    return adder

adder = get_adder()

Each of the four approaches has its pros and cons.  The closure
approach is probably the clearest if you really want to avoid using a
global.  If there were agreement on a best approach, the least we
could do it make it clearer in the docs, assuming you looked and
didn't find anything helpful in the obvious places. :)

A more explicit mechanism could be nice, but would have to pass a
pretty high bar for inclusion into the language.  Here are some
approaches:

* A new keyword, e.g. "persistent", to accompany global and nonlocal.
* A special decorator that identifies persistent local variables in
the function.

So that you're aware, this idea came up a few years ago and involved a
long discussion that eventually lost steam (don't remember why)
[1][2][3].  There are also a couple existing PEPs [4][5] that would be
applicable (my favorite is the given statement).

-eric

[1] https://mail.python.org/pipermail/python-ideas/2011-September/011805.html
[2] https://mail.python.org/pipermail/python-ideas/2011-June/010479.html
[3] https://mail.python.org/pipermail/python-ideas/2011-September/011750.html
[4] "statement local namespaces" (given statement)
http://www.python.org/dev/peps/pep-3150/
[5] "General purpose decorator clause" http://www.python.org/dev/peps/pep-0403/


More information about the Python-ideas mailing list