阻止从子类访问实例变量,而不影响基类

Mar*_*nen 9 python inheritance class python-3.x

假设我有一个简单的类Foo,它来自外部库,因此我无法直接更改它:

class Foo(object):
    def __init__(self, x):
        self.x = x
Run Code Online (Sandbox Code Playgroud)

我想创建一个子类Bar并防止x从实例中更改Bar,但仍然使用xin Bar的方法.

这是我尝试过的,它可能会启发基本的想法,但不幸的是它不起作用:

class Bar(Foo):

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

    @x.setter
    def x(self, value):
        raise NotImplementedError('Do not change x directly, use "do_stuff()" instead')

    def do_stuff(self, value):
        if <something>:
            super().x = value
Run Code Online (Sandbox Code Playgroud)

所以基本上我已经do_stuff()在一个属性周围创建了一些包装函数(),现在我想防止直接更改属性,因为它可能会破坏包装函数的某些功能.这有可能以合理的方式吗?

编辑了我想要的更好的例子.我不是想阻止他们看到变量x,而是从外面改变它do_stuff()

Noc*_*wer 1

如果您愿意完全避免继承,这应该更容易完成:

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()
Run Code Online (Sandbox Code Playgroud)