""" ==================================================================== Example from "Learning Python, 5th Edition" (copyright Mark Lutz). Private and Public declarations for instances of classes, via 2.6+ class decorators. Controls access to attributes stored on an instance, or inherited by it from its classes. Private() declares attribute names that cannot be fetched or assigned outside the subject class, and Public() declares all the names that can. See the book for more details; an extra mix-in class required to handle operator overloading methods correctly in 3.X; and an extension to disable the decorator in -O optimized mode. ==================================================================== """ traceMe = False def trace(*args): if traceMe: print('[' + ' '.join(map(str, args)) + ']') def accessControl(failIf): def onDecorator(aClass): class onInstance: def __init__(self, *args, **kargs): self.__wrapped = aClass(*args, **kargs) def __getattr__(self, attr): trace('get:', attr) if failIf(attr): raise TypeError('private attribute fetch: ' + attr) else: return getattr(self.__wrapped, attr) def __setattr__(self, attr, value): trace('set:', attr, value) if attr == '_onInstance__wrapped': self.__dict__[attr] = value elif failIf(attr): raise TypeError('private attribute change: ' + attr) else: setattr(self.__wrapped, attr, value) return onInstance return onDecorator def Private(*attributes): return accessControl(failIf=(lambda attr: attr in attributes)) def Public(*attributes): return accessControl(failIf=(lambda attr: attr not in attributes)) # self-test, example usage if __name__ == '__main__': import sys @Private('job', 'pay') class Emp1: def __init__(self): self.name = 'Bob' self.job = 'dev' self.pay = 50000 @Public('name') class Emp2: def __init__(self): self.name = 'Sue' self.job = 'dev' self.pay = 50000 x, y = Emp1(), Emp2() print(x.name, y.name) try: print(x.job) except: print('failed correctly =>', sys.exc_info()[1]) try: print(y.job) except: print('failed correctly =>', sys.exc_info()[1])