Welcome, guest | Sign In | My Account | Store | Cart
def public(f):
    '''
    Decorator used to assign the attribute __public__ to methods.
    '''
    f.__public__ = True
    return f

class Protected(object):
    '''
    Base class of all classes that want to hide protected attributes from
    public access.
    '''
    def __new__(cls, *args, **kwd):
        obj = object.__new__(cls)        
        cls.__init__(obj, *args, **kwd)
                                
        def __getattr__(self, name):            
            attr = getattr(obj, name)
            if hasattr(attr, "__public__"):
                return attr
            elif hasattr(cls, "__public__"):
                if name in cls.__public__:
                    return attr                            
            raise AttributeError, "Attribute %s is not public."%name
        
        def __setattr__(self, name, value):
            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("Protected(%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__
        return Proxy()

#
# Example
#

class Counter(Protected):
    __public__ = ["y"]
    def __init__(self, start=0):
        self.n = start
        self.y = 0
                    
    @public            
    def inc(self):
        self.n+=1
        return self.n
        
    @public        
    def dec(self):
        self.n-=1
        return self.n
    
    @public    
    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

    @public            
    def inc(self):
        self.n+=self.step
        return self.n
    
    @public            
    def dec(self):
        self.n-=self.step
        return self.n
    
    def steps(self):
        return self.n/self.step


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

>>> c = Counter()
>>> c.inc()
1
>>> c.dec()
0
>>> c.n
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
  File "C:\Python24\Lib\site-packages\pythonwin\private.py", line 17, in __getattr__
    raise AttributeError, "Attribute %s is not public."%name
AttributeError: Attribute n is not public.
>>> c.y
0


>>> sc = SteppedCounter(step=2)
>>> sc.inc()
2
>>> sc.value()
2
>>> sc.steps()  
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
  File "C:\Python24\Lib\site-packages\pythonwin\private.py", line 17, in __getattr__
    raise AttributeError, "Attribute %s is not public."%name
AttributeError: Attribute steps is not public.

History

  • revision 3 (17 years ago)
  • previous revisions are not available