Private data

Dustan DustanGroups at gmail.com
Sun Mar 18 08:17:53 EDT 2007


On Mar 18, 5:26 am, "Gabriel Genellina" <gagsl-... at yahoo.com.ar>
wrote:
> En Sat, 17 Mar 2007 13:31:01 -0300, Dustan <DustanGro... at gmail.com>
> escribió:
>
> >http://dustangroups.googlepages.com/privateattributesinpython
>
> > This is something that I just threw together this morning, after a
> > eureka moment. It's a way of creating private class attributes and
> > static function variables (I'm not 100% sure if that's the correct
> > terminology, but you get what I mean). I haven't tried to create
> > private instance attributes, mainly because it would just be too
> > difficult, and it would be awful syntax. I'm not considering actually
> > using this, but I do have a couple questions about it.
>
> I feel so dumb, but I can't see how to use it, or what's for. Perhaps an
> example?
>
> --
> Gabriel Genellina

There are two examples - one demonstrating static function variables
and one demonstrating private class attributes. Both perform some kind
of counting. The function returns how many times it's been called.
Here it is:

@PrivateDataEngine(numCalls = 0)
def testPrivateStaticFunctionVariables(internalData):
    """returns the number of times this function has been called."""
    internalData.numCalls += 1
    return internalData.numCalls

There's a comment explaining how the decorator works on the page I
linked you to.

A common pythonic workaround for this is something like this:

def testMutableDefaultArgs(_cache = {'internalData':0}):
    """returns the number of times this function has been called."""
    _cache['internalData'] += 1
    return _cache['internalData']

The default argument only gets evaluated once, and since it's mutable
and being modified in the function, it magically becomes
{'internalData':1} after 1 call and {'internalData':1348372} after
1348372 calls.

The other example, explaining private class attributes, has a method
getNumInstances that returns how many instances have been created.
Here that is:

class TestPrivateClassAttributes(object):
    # pca here obviously stands for Private Class Attributes.
    pcaManager = PrivateDataEngine(numInstances = 0)

    # Notice that the internal data is an implicit parameter that
comes first,
    # even before the self parameter.
    @pcaManager
    def __init__(internalData, self):
        internalData.numInstances += 1

    @staticmethod
    @pcaManager
    def getNumInstances(internalData):
        return internalData.numInstances

    # Don't forget to delete the pcvManager, or it will have all been
in vain.
    del pcaManager

I'm thinking this is going to look rather ugly when the text gets
wrapped; that's why I linked to an external page in the first place.

Notice it requires more advanced usage of the PrivateDataEngine if you
want multiple functions to have access to the same data, as you
normally would in a class.

Note also that the double-decorated method getNumInstances requires
that staticmethod be the first decorator. This is equivalent to the
code "getNumInstances = staticmethod(pcaManager(getNumInstances))". I
got an error when I tried it with pcaManager preceding staticmethod,
so my educated guess is that staticmethods are somehow specially
recognized by the class, and therefore they have to actually BE
staticmethods, not dressed over by a pcaManager.

Now that I think of it, for clarity, pcaManager may not have been a
good name for the function returned by PrivateDataEngine; pcaDecorator
would have been better, seeing as it IS a decorator. Perhaps I'll
change that soon.

The pythonic way would be:

class TestPythonsPrivateClassAttributes(object):
    _numInstances = 0

    def __init__(self):
        # class attributes can be accessed from self.
        self.numInstances += 1

    @staticmethod
    def getNumInstances(internalData):
        return self.numInstances

It should immediately stick out as being much more concise
syntactically, and therefore much less bug-prone.

Obviously, these examples are a lot like "Hello, World!" in their
usefulness; one would very rarely want to track how many times a
function has been called.

Hope that helps.




More information about the Python-list mailing list