隐藏/封装继承的类的所有属性,同时保持功能

时间:2018-07-06 21:10:45

标签: python python-3.x

有没有办法在Cat内隐藏或嵌套Animal属性,同时仍然能够运行跳转功能?具体来说,我想将vars(test)的输出仅作为年龄。我敢肯定我可以通过定义自定义__str__来硬编码不输出哪些特定属性,但是我将为Cat/Animal有很多属性,并且我不想为每个属性手动添加异常个人属性。我也将无法访问Cat类。

def Jump():
    print('Jumped!')

class Cat:
    def __init__(self):
        self.feet = 4
        self.jump = Jump

class Animal(Cat):
    def __init__(self):
        Cat.__init__(self)
        self.age = 3

test = Animal()
test.jump()
print(vars(test))

输出:

  

跳跃的{'feet':4,'jump':,'age':3}

这只是说明我正在尝试执行的代码。实际上,Cat代表已发布的python模块,Animal代表我的自定义模块。

1 个答案:

答案 0 :(得分:1)

如果您更改关系,以使Animal不再是 Cat,而是已经是 Cat ,那么您是对的,animal.jump()将不再起作用。

有很多解决方法。鉴于这种设计已经有多么奇怪了,所以我不知道哪种方法最合适,所以我只列出其中的大部分。

第一类是只显式委派jump的方法。

“正常”方式:

class Animal:
    def __init__(self):
        self.cat = Cat()
    def jump(self):
        return self.cat.jump()

复制每个实例的功能:

class Animal:
    def __init__(self):
        self.cat = Cat()
        self.jump = self.cat.jump

代理到每个实例:

class Animal:
    def __init__(self):
        self.cat = Cat()
        self.jump = lambda: self.cat.jump()

按实例绑定的方法:

class Animal:
    def __init__(self):
        self.cat = Cat()
        self.jump = (lambda self: self.cat.jump()).__get__(self)

动态查找:

class Animal:
    def __init__(self):
        self.cat = Cat()
    def __getattr__(self, name):
        if name == 'jump':
            return getattr(self.cat, name)
        raise AttributeError

动态绑定方法生成:

class Animal:
    def __init__(self):
        self.cat = Cat()
    def __getattr__(self, name):
        if name == 'jump':
            return (lambda self: getattr(self.cat, name)()).__get__(self)
        raise AttributeError

当然,所有这些仅专门委托jump。如果您想委托给所有 Cat函数,方法,也许还有其他属性,而不必事先知道它们是什么,该怎么办?好吧,很明显如何适应其中的大多数,所以我只展示两个。

动态查找:

class Animal:
    def __init__(self):
        self.cat = Cat()
    def __getattr__(self, name):
        return getattr(self.cat, name)

半静态检查对我们可能要委派的各种可能的事情进行了复杂的反映:

class Animal:
    def __init__(self):
        self.cat = cat
        for name, value in inspect.getmembers(self.cat):
            if name.startswith('_'): continue
            if inspect.ismethod(value):
                value = (lambda self: value()).__get__(self)
            elif callable(value):
                value = lambda: value()
            else:
                value = copy.copy(value)
            setattr(self, name, value)