说我有一个简单的类Foo,它来自外部库,因此我不能直接更改它:

class Foo(object):
    def __init__(self, x):
        self.x = x

我想创建一个子类Bar并防止xBar实例更改,但仍在x的方法中使用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

因此,基本上我已经围绕属性创建了一些包装函数(do_stuff()),现在我想防止直接更改该属性,因为这可能会使包装函数的某些功能困惑。这有可能以合理的方式吗?

编辑了,其中提供了我想要的更好示例。我不是要阻止他们看到变量x,而是要从do_stuff()外部进行更改

最佳答案

如果您完全希望避免继承,则这应该更容易实现:

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()

关于python - 防止从子类访问实例变量,而不会影响基类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33368552/

10-12 22:53