Trying to do this is probably a bad idea, but...
It doesn't seem to be do this via "proper" inheritance because of how looking up B.x
works by default. When getting B.x
the x
is first looked up in B
and if it's not found there it's searched in A
, but on the other hand when setting or deleting B.x
only B
will be searched. So for example
>>> class A:
>>> x = 5
>>> class B(A):
>>> pass
>>> B.x
5
>>> del B.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class B has no attribute 'x'
>>> B.x = 6
>>> B.x
6
>>> del B.x
>>> B.x
5
Here we see that first we doesn't seem to be able to delete B.x
since it doesn't exist (A.x
exists and is what gets served when you evaluate B.x
). However by setting B.x
to 6 the B.x
will exist, it can be retrieved by B.x
and deleted by del B.x
by which it ceases to exist so after that again A.x
will be served as response to B.x
.
What you could do on the other hand is to use metaclasses to make B.x
raise AttributeError
:
class NoX(type):
@property
def x(self):
raise AttributeError("We don't like X")
class A(object):
x = [42]
class B(A, metaclass=NoX):
pass
print(A.x)
print(B.x)
Now of course purists may yell that this breaks the LSP, but it's not that simple. It all boils down to if you consider that you've created a subtype by doing this. The issubclass
and isinstance
methods says yes, but LSP says no (and many programmers would assume "yes" since you inherit from A
).
The LSP means that if B
is a subtype of A
then we could use B
whenever we could use A
, but since we can't do this while doing this construct we could conclude that B
actually isn't a subtype of A
and therefore LSP isn't violated.
x
class variable ofB
that you want to delete is really stored inA.__dict__
, so if you managed to delete it, you would also deleteA.x
. Therefore, the closest you can come is hidingA.x
it by givingB
anx
class variable too, as @Keith suggests in his answer. – Arson