Why does base class order matter when overriding #abstractmethods in base classes?
Is it possible to override abstract methods in base classes without depending on base class order?
from abc import ABC, abstractmethod
class A(ABC):
#abstractmethod
def f(self):
raise NotImplementedError
class B:
def f(self):
pass
# class C(A,B): pass # fails
class C(B,A): pass # works
While C(B,A) works, C(A,B) results in
TypeError: Can't instantiate abstract class C with abstract methods f
Related
For example, this abstract class:
from abc import ABC, abstractmethod
class Polygon(ABC):
# abstract method
def noofsides(self):
print("something")
class Triangle(Polygon):
# overriding abstract method
def noofsides(self):
print("I have 3 sides")
...could be written as a superclass and it would do the exact same thing:
class Polygon:
def noofsides(self):
print("something")
class Triangle(Polygon):
# overriding abstract method
def noofsides(self):
print("I have 3 sides")
So I don't see the point in using an abstract class. Can someone explain me please?
Here is my code:
from abc import ABC
from abc import abstractmethod
class Mamifiero(ABC):
"""docstring for Mamifiero"""
def __init__(self):
self.alimentacion = 'carnivoro'
#abstractmethod
def __respirar(self):
print('inhalar... exhalar')
class Perro(Mamifiero):
"""docstring for Perro"""
def __init__(self, ojos=2,):
self.ojos = ojos
I want that perro.respirar() prints 'inhalar... exhalar' but when I want to instantiate a Perro class show me this error. I want to know what is wrong with my script
By definition (read the docs), an abstract call is a class which CANNOT be instantiated until it has any abstract methods not overridden. So as in the Object-Oriented Programming by design.
You have an abstract method Perro.__respirar() not overridden, as inherited from the parent class. Or, override it with a method Perro.__respirar(), and do something there (maybe even call the parent's method; but not in case it is private with double-underscore, of course).
If you want to instantiate Perro, just do not make that method abstract. Make it normal. Because it also has some implementation, which suggests it is a normal base-class'es method, not an abstract method.
You need to override __respirar() abstract method in Perro class as shown below:
from abc import ABC
from abc import abstractmethod
class Mamifiero(ABC):
"""docstring for Mamifiero"""
def __init__(self):
self.alimentacion = 'carnivoro'
#abstractmethod
def __respirar(self):
print('inhalar... exhalar')
class Perro(Mamifiero):
"""docstring for Perro"""
def __init__(self, ojos=2,):
self.ojos = ojos
# You need to override
def __respirar(self):
print('Hello')
I'm working on a kind of lib, and I'm getting an error.
Here is my code. Of course #abc.abstractmethod have to be uncommented
Here are my tests
Sorry couldn't just copy and paste it
I went on the basis that the code below works.
test.py:
import abc
import six
#six.add_metaclass(abc.ABCMeta)
class Base(object):
#abc.abstractmethod
def whatever(self,):
raise NotImplementedError
class SubClass(Base):
def __init__(self,):
super(Base, self).__init__()
self.whatever()
def whatever(self,):
print("whatever")
In the python shell:
>>> from test import *
>>> s = SubClass()
whatever
For my roster module, why am I getting this error:
Can't instantiate abstract class Player with abstract methods _Base__json_builder, _Base__xml_builder
Your issue comes because you have defined the abstract methods in your base abstract class with __ (double underscore) prepended. This causes python to do name mangling at the time of definition of the classes.
The names of the function change from __json_builder to _Base__json_builder or __xml_builder to _Base__xml_builder . And this is the name you have to implement/overwrite in your subclass.
To show this behavior in your example -
>>> import abc
>>> import six
>>> #six.add_metaclass(abc.ABCMeta)
... class Base(object):
... #abc.abstractmethod
... def __whatever(self):
... raise NotImplementedError
...
>>> class SubClass(Base):
... def __init__(self):
... super(Base, self).__init__()
... self.__whatever()
... def __whatever(self):
... print("whatever")
...
>>> a = SubClass()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class SubClass with abstract methods _Base__whatever
When I change the implementation to the following, it works
>>> class SubClass(Base):
... def __init__(self):
... super(Base, self).__init__()
... self._Base__whatever()
... def _Base__whatever(self):
... print("whatever")
...
>>> a = SubClass()
whatever
But this is very tedious , you may want to think about if you really want to define your functions with __ (double underscore) . You can read more about name mangling here .
I got the same error below:
TypeError: Can't instantiate abstract class Animal with abstract methods sound
When I tried to instantiate Animal abstract class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
print("Wow!!")
obj = Animal() # Here
obj.sound()
And also, I got the same error below:
TypeError: Can't instantiate abstract class Cat with abstract methods sound
When I didn't override sound() abstract method in Cat class, then I instantiated Cat class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
print("Wow!!")
class Cat(Animal):
pass # I didn't override "sound()" abstract method
obj = Cat() # Here
obj.sound()
So, I overrided sound() abstract method in Cat class, then I instantiated Cat class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
print("Wow!!")
# I overrided "sound()" abstract method
class Cat(Animal):
def sound(self):
print("Meow!!")
obj = Cat() # Here
obj.sound()
Then, I could solve the error:
Meow!!
Easiest way to make it behave like it did in Python 2 is to use
exec('print("your code")', globals())
This will allow your code to access imports, classes and functions defined in the code will work correctly, etc.
This should only be done w/ code you trust.
I was trying out the below python code:
from abc import ABCMeta, abstractmethod
class Bar:
__metaclass__ = ABCMeta
#abstractmethod
def foo(self):
pass
class Bar2(Bar):
def foo2(self):
print("Foo2")
b = Bar()
b2 = Bar2()
I thought having #abstractmethod will ensure that my parent class will be abstract and the child class would also be abstract as it is not implementing the abstract method. But here, I get no error trying to instantiate both the classes.
Can anyone explain why?
You must set meta-class of Bar class to ABCMeta.
Python 2:
class Bar:
__metaclass__ = ABCMeta
#abstractmethod
def foo(self):
pass
Python 3:
class Bar(object, metaclass=ABCMeta):
#abstractmethod
def foo(self):
pass
I want to ensure that any class that is derived from my class overrides certain methods. If they are not overridden I want to raise a NotImplementedError as soon as possible after compiling begins, rather than when one of the methods are called.
I've found that I can do it with a metaclass like so:
class MetaBaseClass(type):
# list of method names which should be overridden
to_override = ['method_a', 'method_b']
def __init__(cls, name, bases, dct):
for methodName in cls.to_override:
if methodName not in dct:
raise NotImplementedError('{0} must override the {1} method'.format(name, methodName))
super(MetaBaseClass, cls).__init__(name, bases, dct)
class BaseClass(object):
__metaclass__ = MetaBaseClass
def method_a(self):
pass
def method_b(self):
pass
This will raise the error at class definition time if method_a or method_b aren't overridden by class derived from BaseClass.
Is there a better way to do this?
Why not use abstractmethod.
from abc import abstractmethod, ABCMeta
class BaseClass(object):
__metaclass__ = ABCMeta
#abstractmethod
def method_a(self):
pass
#abstractmethod
def method_b(self):
pass
class Inherit(BaseClass):
pass
You will get an error as soon as a user tries to instantiate the Inherit class.
i = Inherit()
TypeError: Can't instantiate abstract class Inherit with abstract methods method_a, method_b