def main():
    bar = Bar(123)
bar.fizz()
bar.buzz()
bar.fizz()
bar.set_x(456)
print(('bar.x =', bar.x))
try:
    bar.x = 123
except AttributeError:
    print('bar.x cannot be set directly')
else:
    raise AssertionError('an AttributeError should have been raised')
bar.mutate_x(789)
bar.fizz()
bar.set_x(0)
bar.fizz()
bar.mutate_x(1)
bar.fizz()
bar.set_x('Hello World')
bar.fizz()


class Foo:

    def __init__(self, x):
        self.x = x

def fizz(self):
    print(self.x)

def buzz(self):
    self.x = None


class Bar:

    def __init__(self, x):
        self.__foo = foo = Foo(x)
self.__copy_methods(foo)

def __copy_methods(self, obj):
    for name in dir(obj):
        if name.startswith('__') or name.endswith('__'):
            continue
attr = getattr(obj, name)
if callable(attr):
    setattr(self, name, attr)

@property
def x(self):
    return self.__foo.x

def set_x(self, value):
    if isinstance(value, int) and value > 0:
        self.__foo.x = value
mutate_x = set_x
if __name__ == '__main__':
    main()
Запретить доступ к переменной экземпляра из подкласса, не затрагивая базовый класс