Welcome, guest | Sign In | My Account | Store | Cart
class WithProtection(object):
    '''
    WithProtection can be used as a base class for all classes that 
    want true protection of user defined attributes mangled with a 
    single underscore "_". 
    '''    
    def __new__(cls, *args, **kwd):        
        obj = object.__new__(cls)        
        cls.__init__(obj, *args, **kwd)
        
        def __getattr__(self, name):            
            attr = getattr(obj, name)
            if name.startswith("_"):
                if name.startswith("__") and name.endswith("__"):
                    return attr
            else:
                return attr
            raise AttributeError, "Attribute %s is not public."%name
        
        def __setattr__(self, name, value):
            if name.startswith("__") and name.endswith("__"):
                raise AttributeError,"magic attributes are write protected."
            attr = getattr(obj, name)                    
            cls.__setattr__(self, name, value)
                    
        # Magic methods defined by cls must be copied to Proxy.
        # Delegation using __getattr__ is not possible.

        def is_own_magic(cls, name, without=[]):
            return name not in without and\
                   name.startswith("__") and name.endswith("__")

        Proxy = type("WithProtection(%s)"%cls.__name__,(),{})
        
        for name in dir(cls):
            if is_own_magic(cls,name, without=dir(Proxy)):
                try:
                    setattr(Proxy, name, getattr(obj,name))
                except TypeError:
                    pass
                
        Proxy.__getattr__ = __getattr__        
        Proxy.__setattr__ = __setattr__
        proxy = Proxy()        
        return proxy 

#
# Example
#

class Counter(WithProtection):    
    def __init__(self, start=0):
        self._n = start
                    
    def inc(self):
        self._n+=1
        return self._n
            
    def dec(self):
        self._n-=1
        return self._n    
    
    def value(self):
        return self._n

#
# Enhanced example using inheritance
#

class SteppedCounter(Counter):
    def __init__(self, start=0, step=1):
        super(SteppedCounter,self).__init__(start=start)
        self.step = step        
    
    def inc(self):
        self._n+=self.step
        return self._n
    
    def __add__(self, k):
        return self._n+k
    
    def dec(self):
        self._n-=self.step
        return self._n
    
    def steps(self):
        return self._n/self.step

################################################################
#   Python Session
################################################################

>>> sc = SteppedCounter()
>>> sc.step
1
>>> sc._n
Traceback (most recent call last):
  ....
AttributeError: Attribute _n is not public.
>>> sc.inc()
1
>>> sc+8
9

History