On Thu, 2008-11-13 at 11:19 -0600, Chris Mellon wrote: > On Thu, Nov 13, 2008 at 11:16 AM, Joe Strout <[EMAIL PROTECTED]> 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 ' > > > > This appears to work fine, but it feels a little unclean, having stuff in > > the method signature that is only meant for internal use. Naming the > > parameter with an underscore "_count" 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? > > > > 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. But then, if I renamed a function, I'd have to change all > > the callers anyway. So maybe this is better. What do y'all think? > > > > Static storage is a way of preserving state. Objects are a way of > encapsulating state and behavior. Use an object.
He is using an object. Specifically, he's using a function object. Though perhaps you meant put it into a class. Here are a few essays into the matter >>> def foo(): ... foo._count += 1 ... return ("spam " * foo.count).rstrip() ... >>> foo._count=0 >>> foo() 'spam' >>> foo() 'spam spam' >>> Simple and straightforward, and _count is still encapsulated in the function, but it's kind of ugly, because when the function has been defined, it is not functional. Attempt #2 -- put it in a decorator >>> def add_counter(f): ... f._count = 0 ... return f ... >>> @add_counter ... def foo(): ... foo._count += 1 ... return ("spam " * foo._count).rstrip() >>> foo() 'spam' >>> foo() 'spam spam' >>> Now it's complete as soon as the function is defined, but the decorator is tightly bound to the function, in its use of _count. I find that kind of ugly. This is the first decorator I've written that doesn't define a function inside itself. Try three. Let's put it in a class: >>> class Foo(object): ... def __init__(self, counter_start=0): ... self._count = counter_start ... def __call__(self): ... self._count += 1 ... return ("spam " * self._count).rstrip() ... >>> foo = Foo() >>> foo() 'spam' >>> foo() 'spam spam' >>> Essentially, this has the same behavior as the other two. But it looks cleaner, and you don't have to worry about coupling separate functions, or refering to a function by name within itself (because you have self to work with). But the "object" semantics are essentially the same, and state is just as legitimately preserved on a function object as a Foo object. Cheers, Cliff -- http://mail.python.org/mailman/listinfo/python-list