using "private" parameters as static storage?

Matimus mccredie at gmail.com
Thu Nov 13 12:38:11 EST 2008


On Nov 13, 9:16 am, Joe Strout <j... at strout.net> wrote:
> One thing I miss as I move from REALbasic to Python is the ability to  
> have static storage within a method -- i.e. storage that is persistent  
> between calls, but not visible outside the method.  I frequently use  
> this for such things as caching, or for keeping track of how many  
> objects a factory function has created, and so on.
>
> Today it occurred to me to use a mutable object as the default value  
> of a parameter.  A simple example:
>
> def spam(_count=[0]):
>       _count[0] += 1
>       return "spam " * _count[0]
>
>  >>> spam()
> 'spam '
>  >>> spam()
> 'spam spam '
>

Don't Do this, it is confusing and there are definitely (many) better
facilities in python for handling saved state.


> Ooh, for a change I had another thought BEFORE hitting Send rather  
> than after.  Here's another trick:
>
> def spam2():
>       if not hasattr(spam2,'count'):spam2.count=0
>       spam2.count += 1
>       return "spam2 " * spam2.count


This is definitely preferred over the first. However the preferred
method is just to use a class. Preserving state is what classes are
for.

>>> class Spam(object):
...     def __init__(self):
...         self._count = 0
...     def spam(self):
...         self._count += 1
...         return " ".join("spam" for _ in xrange(self._count))
...
>>> x = Spam()
>>> print x.spam()
spam
>>> print x.spam()
spam spam
>>> print x.spam()
spam spam spam

It also gives you the ability to have two compleately separate
instances of the same state machine.

>>> y = Spam()
>>> print y.spam()
spam
>>> print y.spam()
spam spam
>>> print y.spam()
spam spam spam
>>>

You can use it like a function if you need to for convenience or
backwards compatibility.:

>>> spam = Spam().spam
>>> print spam()
spam
>>> print spam()
spam spam
>>> print spam()
spam spam spam

Or:

>>> class Spam(object):
...     def __init__(self):
...         self._count = 0
...
...     def spam(self):
...         self._count += 1
...         return " ".join("spam" for _ in xrange(self._count))
...
...     __call__ = spam
...
>>> spam = Spam()
>>> print spam()
spam
>>> print spam()
spam spam
>>> print spam()
spam spam spam


Matt



More information about the Python-list mailing list