Reputation: 211
I have an assignment from an instructor trying to teach OOP in python. I'm pretty familiar with OOP in C++ and C# but having a difficulty figuring out what is going on in some of my code. It works and both classes function as I want but I had to add some weird code for it to work and I don't understand why.
Specifically referencing the code starting in line 64
class Cone(Cylinder):
#Constructor
def __init__ (self, radius, height):
Cylinder.__init__(self, radius, height)
self.calcVolume()
def calcVolume(self):
Cylinder.calcVolume(self)
self.__volume = Cylinder.GetVolume(self) * (1.0/3.0)
So when implementing Cone
I don't understand why the Cylinder.calcVolume()
is not called when the cone's constructor calls the cylinder's constructor. The code would make more sense to me if it was implicitly called but im forced to call the method explicitly. Some guidance or explanation would be awesome.
After Posting I made this change does it make more sense?
class Cone(Cylinder):
#Constructor
def __init__ (self, radius, height):
Cylinder.__init__(self, radius, height)
self.calcVolume()
def calcVolume(self):
self.__volume = self.GetBase().GetArea() * self.GetHeight() * (1.0/3.0)
Upvotes: 3
Views: 2909
Reputation: 24304
This is what happens when you call Cone.__init__()
:
Cylinder.__init__()
,self.calcVolume()
,Cone
type,Cone.calcVolume()
instead of Cylinder.calcVolume()
.During __init__()
I think you want to call:
Cone.calcVolume(self)
in Cone.__init__()
, orCylinder.calcVolume(self)
in Cylinder.__init__()
.Of course, if you were using new style classes (inheriting from object
) then you could just use type(self).calcVolume(self)
; however type(self)
on an old-style class is going to give you the instance
type instead of the actual class, which isn't going to work in your case.
full example:
class Circle():
#Constructor
def __init__ (self, radius):
self.__radius = radius
self.calcArea()
def calcArea(self, PI = 3.14):
self.__area = (self.__radius**2) * PI
#Get Functions
def GetArea(self):
return self.__area
def GetRadius(self):
return self.__radius
#Set Functions
def SetRadius(self, radius):
self.__radius = radius
self.calcArea()
class Cylinder():
#Constructor
def __init__(self, radius, height):
self.__height = height
self.__base = Circle(radius)
Cylinder.calcVolume(self)
def calcVolume(self):
self.__volume = self.__base.GetArea() * self.__height
#Get Functions
def GetVolume(self):
return self.__volume
def GetBase(self):
return self.__base
def GetRadius(self):
return self.__base.GetRadius()
def GetHeight(self):
return self.__height
#Set Functions
def SetRadius(self, radius):
self.__base.SetRadius(radius)
self.calcVolume()
def SetHeight(self, height):
self.__height = height
self.calcVolume()
class Cone(Cylinder):
#Constructor
def __init__ (self, radius, height):
Cylinder.__init__(self, radius, height)
Cone.calcVolume(self)
def calcVolume(self):
Cylinder.calcVolume(self)
self.__volume = Cylinder.GetVolume(self) * (1.0/3.0)
#Get Functions
def GetVolume(self):
return self.__volume
#Set Functions
def SetRadius(self, radius):
Cylinder.SetRadius(self, radius)
self.calcVolume()
def SetHeight(self, height):
Cylinder.SetHeight(self, height)
self.calcVolume()
def main():
cylinder = Cylinder(5, 6)
cone = Cone(5, 6)
circle = Circle(5)
print cylinder.GetVolume()
print cone.GetVolume()
print circle.GetArea()
cone.SetHeight(7)
print cone.GetVolume()
main()
Upvotes: 3
Reputation: 137290
Rule is pretty straightforward: when the method is to be called, its name is resolved according to Method Resolution Order (it is tricky, as Python has multiple inheritance).
After the name is resolved, Python stops searching (I am simplifying). It is up to the specific method to call parent class's method (or any other method). Doing it implicitly could be a common cause of problems (eg. when you want to override some method from parent class).
Also, to invoke parent method use super()
. Instead of writing this in Cone
class:
Cylinder.__init__(self, radius, height)
write this:
super(Cone, self).__init__(self, radius, height)
That makes it more flexible: it just delegates finding proper method to MRO, which then checks parent classes in specific order (in this case, it will indeed find Cylinder.__init__
).
More reading:
super()
in Python 2.7,super()
,Upvotes: 3