没有继承属性的Python子类

时间:2016-07-08 20:46:30

标签: python class oop inheritance

我想创建一个表面上看起来像是另一个类的子类的Python类,但实际上并没有继承它的属性。

例如,如果我的班级名为B,我希望isinstance(B(), A)返回True,以及issubclass(B, A),但我不会&#39 ; t希望B具有为A定义的属性。这可能吗?

注意:我无法控制A的实施。

为什么我关心:我正在使用的模块检查传递的对象是A的子类。我想在B中定义必要的属性,而不继承A中定义的多余属性(我无法控制其实现),因为我使用__getattr__传递一些属性调用在一个包装的类上,如果这些属性是由A的继承定义的,则__getattr__不会被调用。

5 个答案:

答案 0 :(得分:3)

在Python3中,覆盖特殊方法__getattribute__。这使您几乎可以完全控制属性查找。有一些极端情况所以请仔细检查文档(它是语言参考手册的第3.3.2节)。

答案 1 :(得分:3)

使用abstract base classes使一个看似无关的类B成为A的子类,而不继承它:

from abc import ABCMeta
class A (metaclass=ABCMeta):
    def foo (self):
        print('foo')

class B:
    def bar (self):
        print('bar')

A.register(B)

然后使用,它会给出所需的结果并显示为子类型,而实际上没有任何基类型的成员:

>>> issubclass(B, A)
True
>>> b = B()
>>> isinstance(b, A)
True
>>> b.foo()
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    b.foo()
AttributeError: 'B' object has no attribute 'foo'
  

我正在使用__getattr__将一些属性调用传递给包装类,如果这些属性是由A的继承定义的,则__getattr__将不会被调用。

对于使用普通属性解析找到的成员,不会调用

__getattr__。您可以改用__getattribute__

但是,如果你正在做的是覆盖基类A的行为,那么我不明白为什么简单地覆盖这些方法不是一个选择:

class A:
    def doSomething (self);
        print('Do not do this!')

class B:
    def __init__ (self, wrapper):
        self.wrapper = wrapper

    def doSomething (self):
        print('Doing something else instead!')
        self.wrapper.doSomething()

答案 2 :(得分:2)

您可以实现__getattribute__来为不在B中的属性引发AttributeErrors:

class A(object):
    def __init__(self):
        self.foo = 1

    def bar(self):
        pass

class B(A):
    def __init__(self):
        self.baz = 42

    def __getattribute__(self, attr):
        if attr in ('foo', 'bar'):
            raise AttributeError()
        return super(B, self).__getattribute__(attr)

我很好奇,你为什么要这样做?

答案 3 :(得分:1)

我希望这能满足你(我认为它有点黑客):

class A:
    attribute = "Hello"
    pass

class B(A):
    def __getattribute__(self, name):
        if name == "__dict__":
            return super().__getattribute__(name)
        if name in type(self).__dict__:
            return type(self).__dict__[name]
        if name in self.__dict__:
            return self.__dict__[name]
        raise AttributeError("type object '{}' has no attribute '{}'".format(type(self).__name__, name))

现在让我们测试一下:

>>> a = A()
>>> a.attribute
'Hello'
>>> b = B()
>>> b.attribute
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "file.py", line 13, in __getattribute__
    raise AttributeError("type object '{}' has no attribute '{}'".format(type(self).__name__, name))
AttributeError: type object 'B' has no attribute 'attribute'

不幸的是,类B本身继承了属性,所以会发生这种情况:

>>> B.attribute
'Hello'

我希望它不重要,如果你需要使用元类(可能会非常讨厌)。

答案 4 :(得分:0)

只要您在__init__方法中定义属性并覆盖该方法,B就无法运行A的{​​{1}}代码,并且因此没有定义属性等。删除方法会更难,但似乎超出了问题的范围。