Take the following minimal example:
import abc
class FooClass(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def FooMethod(self):
raise NotImplementedError()
def main():
derived_type = type('Derived', (FooClass,), {})
def BarOverride(self):
print 'Hello, world!'
derived_type.FooMethod = BarOverride
instance = derived_type()
Running main()
gets you:
TypeError: Can't instantiate abstract class Derived with abstract methods FooMethod
(The exception occurs on the instance = derived_type()
line.)
But FooMethod
shouldn't be abstract: I've overridden it with BarOverride
. So, why is this raising exceptions?
Disclaimer: Yes, I could use the explicit class
syntax, and accomplish the exact same thing. (And even better, I can make it work!) But this is a minimal test case, and the larger example is dynamically creating classes. :-) And I'm curious as to why this doesn't work.
Edit: And to prevent the other obvious non-answer: I don't want to pass BarOverride
in the third argument to type
: In the real example, BarOverride
needs to have derived_type
bound to it. It is easier to do this if I can define BarOverride
after the creation of derived_type
. (If I can't do this, then why?)
Because the docs say so:
Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported. The abstractmethod() only affects subclasses derived using regular inheritance; “virtual subclasses” registered with the ABC’s register() method are not affected.
A metaclass is only called when a class is defined. When abstractmethod
has marked a class as abstract that status won't change later.
Jochen is right; the abstract methods are set at class creation and won't me modified just because you reassign an attribute.
You can manually remove it from the list of abstract methods by doing
DerivedType.__abstractmethods__ = frozenset()
or
DerivedType.__abstractmethods__ = frozenset(
elem for elem in DerivedType.__abstractmethods__ if elem != 'FooMethod')
as well as setattr
, so it doesn't still think that FooMethod
is abstract.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With