I have a subclass and I want it to not include a class attribute that's present on the base class.
I tried this, but it doesn't work:
>>> class A(object):
... x = 5
>>> class B(A):
... del x
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
class B(A):
File "<pyshell#1>", line 2, in B
del x
NameError: name 'x' is not defined
How can I do this?
Think carefully about why you want to do this; you probably don't. Consider not making B inherit from A.
The idea of subclassing is to specialise an object. In particular, children of a class should be valid instances of the parent class:
If you implement this behaviour (with e.g.
x = property(lambda: AttributeError)
), you are breaking the subclassing concept, and this is Bad.You can use
delattr(class, field_name)
to remove it from the class definition.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 gettingB.x
thex
is first looked up inB
and if it's not found there it's searched inA
, but on the other hand when setting or deletingB.x
onlyB
will be searched. So for exampleHere 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 evaluateB.x
). However by settingB.x
to 6 theB.x
will exist, it can be retrieved byB.x
and deleted bydel B.x
by which it ceases to exist so after that againA.x
will be served as response toB.x
.What you could do on the other hand is to use metaclasses to make
B.x
raiseAttributeError
: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
andisinstance
methods says yes, but LSP says no (and many programmers would assume "yes" since you inherit fromA
).The LSP means that if
B
is a subtype ofA
then we could useB
whenever we could useA
, but since we can't do this while doing this construct we could conclude thatB
actually isn't a subtype ofA
and therefore LSP isn't violated.You don't need to delete it. Just override it.
or simply don't reference it.
Or consider a different design (instance attribute?).
Maybe you could set
x
asproperty
and raise AttributeError whenever someone try to access it.None of the answers had worked for me.
For example
delattr(SubClass, "attrname")
(or its exact equivalent,del SubClass.attrname
) won't "hide" a parent method, because this is not how method resolution work. It would fail withAttributeError('attrname',)
instead, as the subclass doesn't haveattrname
. And, of course, replacing attribute withNone
doesn't actually remove it.Let's consider this base class:
I know only two only ways to subclass it, hiding the
expect
attribute:Using a descriptor class that raises
AttributeError
from__get__
. On attribute lookup, there will be an exception, generally indistinguishable from a lookup failure.The simplest way is just declaring a property that raises
AttributeError
. This is essentially what @JBernardo had suggested.However, this only works for instances, and not for the classes (the
hasattr(SpanishInquisition, "expect") == True
assertion would be broken).If you want all the assertions above to hold true, use this:
I believe this is the most elegant method, as the code is clear, generic and compact. Of course, one should really think twice if removing the attribute is what they really want.
Overriding attribute lookup with
__getattribute__
magic method. You can do this either in a subclass (or a mixin, like in the example below, as I wanted to write it just once), and that would hide attribute on the subclass instances. If you want to hide the method from the subclass as well, you need to use metaclasses.This looks worse (more verbose and less generic) than the method above, but one may consider this approach as well.
Note, this does not work on special ("magic") methods (e.g.
__len__
), because those bypass__getproperty__
. Check out Special Method Lookup section of the Python documentation for more details. If this is what you need to undo, just override it and callobject
's implementation, skipping the parent.Needless to say, this only applies to the "new-style classes" (the ones that inherit from
object
), as magic methods and descriptor protocols aren't supported there. Hopefully, those are a thing of the past.