Suppose I have a base class with unimplemented methods as follows:
class Polygon():
def __init__(self):
pass
def perimeter(self):
pass
def area(self):
pass
Now, let's say one of my colleagues uses the Polygon class to create a subclass as follows:
import math
class Circle(Polygon):
def __init__(self, radius):
self.radius = radius
def perimeter(self):
return 2 * math.pi * self.radius
(H/Sh)e has forgotten to implement the area() method.
How can I force the subclass to implement the parent's area() method?
this could be your parent class:
class Polygon():
def __init__(self):
raise NotImplementedError
def perimeter(self):
raise NotImplementedError
def area(self):
raise NotImplementedError
although the problem will be spotted at runtime only, when one of the instances of the child classes tries to call one of these methods.
a different version is to use abc.abstractmethod.
from abc import ABC, abstractmethod
import math
class Polygon(ABC):
#abstractmethod
def __init__(self):
pass
#abstractmethod
def perimeter(self):
pass
#abstractmethod
def area(self):
pass
class Circle(Polygon):
def __init__(self, radius):
self.radius = radius
def perimeter(self):
return 2 * math.pi * self.radius
# def area(self):
# return math.pi * self.radius**2
c = Circle(9.0)
# TypeError: Can't instantiate abstract class Circle
# with abstract methods area
you will not be able to instantiate a Circle without it having all the methods implemented.
this is the python 3 syntax; in python 2 you'd need to
class Polygon(object):
__metaclass__ = ABCMeta
also note that for the binary special functions __eq__(), __lt__(), __add__(), ... it is better to return NotImplemented instead of raising NotImplementedError.
You can raise NotImplementedError exception in base class method.
class Polygon:
def area(self):
raise NotImplementedError
Also you can use #abc.abstractmethod, but then you need to declare metaclass to be abc.ABCMeta, which would make your class abstract. More about abc module
That's exactly what NotImplementedError are used for :)
In your base class
def area(self):
raise NotImplementedError("Hey, Don't forget to implement the area!")
Related
I have been learning OOPS in python and finding it a bit different from that of Java. In the below code I have written an abstract class and implemented it. Is it the right way to define the attributes of an abstract class?
class Vehicle(ABC):
#property
#abstractmethod
def color(self):
pass
#property
#abstractmethod
def regNum(self):
pass
class Car(Vehicle):
def __init__(self,color,regNum):
self.color = color
self.regNum = regNum
Is this a better way to do this?
from abc import ABC, abstractmethod
class Vehicle(ABC):
#abstractmethod
def __init__(self,color,regNum):
self.color = color
self.regNum = regNum
class Car(Vehicle):
def __init__(self,color,regNum):
self.color = color
self.regNum = regNum
car = Car("red","EX9890")
If you want to define abstract properties in an abstract base class, you can't have attributes with the same names as those properties, and you need to define concrete implementations of the properties in the concrete child class:
from abc import ABC, abstractmethod
class Vehicle(ABC):
#property
#abstractmethod
def color(self):
pass
#property
#abstractmethod
def regNum(self):
pass
class Car(Vehicle):
def __init__(self, color, regNum):
self._color = color
self._regNum = regNum
#property
def color(self):
return self._color
#property
def regNum(self):
return self._regNum
c = Car("foo", "bar") # works fine; would not work if abstract methods weren't implemented
Which are the differences or advantages of Circle1 and Circle2? Is there a more correct way than the other? The only advantage is that in Circle2 I can inherit it?
class Geometry(object):
def __init__(self, x, y):
self.ptsx = x
self.ptsy = y
class Circle1(Geometry):
def __init__(self, radius):
self.radius = radius
def area(self):
def circle_formula(radius):
return 3.14*radius
return circle_formula(self.radius)
class Circle2(Geometry):
def __init__(self, radius):
self.radius = radius
def area(self):
return self.circle_formula(self.radius)
#staticmethod
def circle_formula(radius):
return 3.14*radius
I know that the correct way would be that the #staticmethod of Cicle2 would be a function like area_formula and when inheriting it, rewrite it. But my doubt is, if I really have to use an auxiliary function that only is going to live inside a specific class, what is the most correct way to implement it?
The main difference between those two classes, is that, if you add staticmethod to a method, you can access to that method without instantiating the class.
I mean, I could do: Circle2.circle_formula(2).
In Circle1, you should instantiate the class to access to the method to calculate the area;
my_circle = Circle1(2)
my_circle.area()
But, in the case that you are presenting, I would add the logic inside the area method, as the Circle1 is implemented, without using a function inside of it. Like this:
class Circle1(Geometry):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14*radius
I am trying to write a base abstract class that has some properties that will be initialized using a constructor. So far I have this:
from abc import ABC, abstractmethod
class A(ABC):
def __init__(self, n, *params):
self.n = n
self.initialize_params(*params) #I want to do this in all subsclasses of A
def initialize_params(self, *params)
pass
#abstractmethod
def do(self):
pass
class B(A):
def __init__(self, m, n, *super_params):
self.m = m
super(A, self).__init__(n, *super_params)
def do(self):
print("this is B")
But this will throw TypeError because of instantiation of A in __init__ of B. What is the correct way of doing this?
You seem to have a couple of mistakes:
from abc import ABC, abstractmethod
class A(ABC):
def __init__(self, n, *params):
self.n = n
self.initialize_params(*params) #I want to do this in all subsclasses of A
def initialize_params(self, *params):
pass
#abstractmethod
def do(self):
pass
class B(A):
def __init__(self, m, n, *super_params):
self.m = m
super().__init__(n, *super_params) # correct way to use super() to call init
def do(self):
print("this is B")
b = B(1,2)
b.do()
Note that you missed self. infront of initialize_params() and you didn't seem to be using super() correctly.
I have two abstract Classes with two methods: getArea(width, height) and getPerimeter(width, height). Those methods are abstract too, so they can be (or not) implemented in a derived class (In my case they must be implemented). In C# I could write IRectangle.getArea(){} or IParallelogram.getPerimeter(){} and simply make implementation. How can I do this in Python? I think that I have to use something like super(IRectangle, self).getArea() but I am not sure how.
from abc import ABC, abstractmethod
class IRectangle(ABC):
#abstractmethod
def getArea(width, height):
pass
#abstractmethod
def getPerimeter(width, height):
pass
class IParallelogram(ABC):
#abstractmethod
def getArea(parHeight, parBase):
pass
#abstractmethod
def getPerimeter(parHeight, parBase):
pass
class Calculate (IParallelogram, IRectangle):
You would just make a class that inherits from the abstract class and overrides the abstract methods like you would write a regular method.
class A(ABC):
#abstractmethod
def f(self):
pass
class B(A):
def f(self):
print ('hello')
If you want to override it but make it do nothing:
class B(A):
def f(self):
pass
Your class hierarchy is upside down. First, you would define a more generic class like Shape as the (abstract) root of the hierarchy.
class Shape(ABC):
#abstractmethod
def getArea(self):
pass
#abstractmethod
def getPerimeter(self):
pass
Then, the concrete classes IRectangle and IParallelogram would implement getArea and getPerimeter appropriately.
class IRectangle(Shape):
def getArea(self):
...
def getPerimeter(self):
...
class IParallelogram:
def getArea(self):
...
def getPerimeter(self):
...
Suppose I have a base class with unimplemented methods as follows:
class Polygon():
def __init__(self):
pass
def perimeter(self):
pass
def area(self):
pass
Now, let's say one of my colleagues uses the Polygon class to create a subclass as follows:
import math
class Circle(Polygon):
def __init__(self, radius):
self.radius = radius
def perimeter(self):
return 2 * math.pi * self.radius
(H/Sh)e has forgotten to implement the area() method.
How can I force the subclass to implement the parent's area() method?
this could be your parent class:
class Polygon():
def __init__(self):
raise NotImplementedError
def perimeter(self):
raise NotImplementedError
def area(self):
raise NotImplementedError
although the problem will be spotted at runtime only, when one of the instances of the child classes tries to call one of these methods.
a different version is to use abc.abstractmethod.
from abc import ABC, abstractmethod
import math
class Polygon(ABC):
#abstractmethod
def __init__(self):
pass
#abstractmethod
def perimeter(self):
pass
#abstractmethod
def area(self):
pass
class Circle(Polygon):
def __init__(self, radius):
self.radius = radius
def perimeter(self):
return 2 * math.pi * self.radius
# def area(self):
# return math.pi * self.radius**2
c = Circle(9.0)
# TypeError: Can't instantiate abstract class Circle
# with abstract methods area
you will not be able to instantiate a Circle without it having all the methods implemented.
this is the python 3 syntax; in python 2 you'd need to
class Polygon(object):
__metaclass__ = ABCMeta
also note that for the binary special functions __eq__(), __lt__(), __add__(), ... it is better to return NotImplemented instead of raising NotImplementedError.
You can raise NotImplementedError exception in base class method.
class Polygon:
def area(self):
raise NotImplementedError
Also you can use #abc.abstractmethod, but then you need to declare metaclass to be abc.ABCMeta, which would make your class abstract. More about abc module
That's exactly what NotImplementedError are used for :)
In your base class
def area(self):
raise NotImplementedError("Hey, Don't forget to implement the area!")