using "private" parameters as static storage?

Bruno Desthuilliers bruno.42.desthuilliers at websiteburo.invalid
Fri Nov 14 11:31:43 CET 2008


Joe Strout a écrit :
> One thing I miss as I move from REALbasic to Python is the ability to 
> have static storage within a method

s/method/function/

> -- 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 '
> 
> This appears to work fine, but it feels a little unclean, having stuff 
> in the method signature that is only meant for internal use.

It's indeed a hack. But it's a very common one, and

>  Naming the 
> parameter with an underscore "_count"

is also a pretty idiomatic way to warn that it's implementation-only.

> makes me feel a little better 
> about it.

>  But then, adding something to the module namespace just for 
> use by one function seems unclean too.

> What are your opinions on this idiom?  Is there another solution people 
> generally prefer?

If it's really in a *method*, you can always use a class (or instance, 
depending on concrete use case) attribute. Else, if you really insist on 
cleanliness, you can define your own callable:

class Spammer(object):
     def __init__(self):
         self._count = 0
     def __call__(self):
         self._count += 1
         return "spam " * self._count

spam = Spammer()

But this might be a little overkill for most concrete use case.

NB : you'll also have to implement __get__ if you want Spammer instances 
to be used as methods.

> 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 doesn't expose any uncleanliness outside the function at all.  The 
> drawback is that the name of the function has to appear several times 
> within itself, so if I rename the function, I have to remember to change 
> those references too.

There's another drawback:

old_spam2 = spam2

def spam2():
    print "yadda yadda", old_spam2()


Remember that Python functions are ordinary objects...




More information about the Python-list mailing list