"""
Dekorator klasy z deklaracjami atrybutów jako prywatne oraz publiczne.

Kontroluje dostęp do atrybutów przechowywanych w instancji lub dziedziczonych przez nią po klasach. Private deklaruje nazwy atrybutów, których nie można pobrać lub przypisać z zewnątrz udekorowanej klasy. Public deklaruje nazwy atrybutów, które można pobrać lub przypisać z zewnątrz.

Uwaga: działa jedynie dla jawnie wymienionych atrybutów. Metody przeciążania operatorów __X__ wykonywane w sposób niejawny dla operacji wbudowanych nie wywołują metod __getattr__ ani __getattribute__ w klasach i ztego powodu nie będą delegowane do żadnego opakowanego obiektu, które je definiują. Jeśli to konieczne, należy tutaj dodać metody __X__ w celu przechwycenia i wydelegowania nazw wbudowanych.
"""

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('pobranie:', attr)
                if failIf(attr):
                    raise TypeError('pobranie atrybutu prywatnego, ' + attr)
                else:
                    return getattr(self.__wrapped, attr)

            def __setattr__(self, attr, value):
                trace('ustawienie:', attr, value)
                if attr == '_onInstance__wrapped':
                    self.__dict__[attr] = value
                elif failIf(attr):
                    raise TypeError('modyfikacja atrybutu prywatnego, ' + 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))

