Reputation: 473
I'm trying to make an example program in Python 2.7 which saves/shares states between two functions. You call a function, next time you call a function, it should remember the previous value. Here is my current code:
def stuff():
global x
x = 100
def f():
global x
x = x * 2
return x
def g():
global x
x = x * 4
return x
return (f, g)
a,b = stuff()
print(a());
This code works, BUT the catch is that x
must not be considered as a global variable outside the scope of stuff()
... (That is the whole point of embedding x within stuff()
in the first place). So, would x
be global, or is it local to stuff()
?
Upvotes: 3
Views: 2558
Reputation: 172229
Easiest and least hacky solution, use a class:
class stuff(object):
x = 100
def f(self):
self.x = self.x * 2
return self.x
def g(self):
self.x = self.x * 4
return self.x
Result:
>>> s = stuff()
>>> s.f()
200
>>> s.g()
800
You want to prevent people from accessing x
from outside the functions at all. The way you do that in Python is by prefixing it with an underscore:
class stuff(object):
_x = 100
def f(self):
self._x = self._x * 2
return self._x
def g(self):
self._x = self._x * 4
return self._x
This tells other Python programmers that it is internal, and not to access it, except on their own risk. You seem to want to prevent even this, but you can't. You can even access the closure in the Python 3 nonlocal example as well:
def stuff():
x = 100
def f():
nonlocal x
x = x * 2
return x
return f
>>> a = stuff()
>>> a()
200
>>> a()
400
>>> a.__closure__[0].cell_contents
400
So you aren't preventing anyone from fiddling with it, you just make the fiddling it obscure and brittle. and more likely to fail. As such you just end up making things more difficult for everyone involved.
Upvotes: 3
Reputation: 2357
If you need to support python 2.X, @georgek's answer is the best, but a lot of people don't realize that you can add attributes to functions. A common idiom is to use a list of a single element to hold the variable.
def stuff():
x = [100]
def g():
x[0] = x[0]*2
return x[0]
def h():
x[0] = x[0]*4
return x[0]
return (g,h)
a, b = stuff()
print(a())
This works because you never assign to x itself in the internal scopes, so it doesn't rebind the variable and shadow the closure.
Upvotes: 3
Reputation: 877
You can use a function without global:
>>> def f():
... f.x = 100
... def g():
... f.x = f.x * 2
... return f.x
... def h():
... f.x = f.x * 4
... return f.x
... return (g, h)
...
>>> a, b = f()
>>> a()
200
>>> b()
800
>>> a()
1600
>>>
Upvotes: 0