Python: how to reference member variables
I am learning Python at Codecademy and I am very confused. I cannot figure out how to access the member variables (I hope they are called). Here is a piece of code I wrote to demonstrate my confusion:
class Triangle(object):
number_of_sides = 3
def __init__(self, angle1, angle2, angle3):
self.angle1 = angle1
self.angle2 = angle2
self.angle3 = angle3
def check_angles(self):
return self.angle1 + self.angle2 + self.angle3 == 180
class Equilateral(Triangle):
angle = 60
def __init__(self):
self.angle1 = self.angle
self.angle2 = self.angle
self.angle3 = self.angle
So, in a subclass Equilateral angle1
, angle2
, angle3
are not included as parameters __init__
. However, the code below is __init__
reinitialized model
, color
and mpg
. Why is this? Shouldn't this just be inherited like in the above code with a subclass Equilateral
? I don't understand why they were written differently.
class Car(object):
condition = "new"
def __init__(self, model, color, mpg):
self.model = model
self.color = color
self.mpg = mpg
def display_car(self):
print "This is a %s %s with %s MPG." %(self.color, self.model, str(self.mpg))
def drive_car(self):
self.condition = "used"
class ElectricCar(Car):
def __init__(self, model, color, mpg, battery_type):
self.model = model
self.color = color
self.mpg = mpg
self.battery_type = battery_type
source to share
However, in the code below, init reinitializes the model, color and mpg. Why is this?
As the author ElectricCar
wants the user to be able to initialize ElectricCar
with four parameters.
ec = ElectricCar('xyz-500', 'blue', 0.5, 'boxy')
However, they had to pass arguments to the base class method __init__
:
class ElectricCar(Car):
def __init__(self, model, color, mpg, battery_type):
super(ElectricCar, self).__init__(model, color, mpg)
self.battery_type = battery_type
In the case, EquilateralTriangle
all angles are the same and must be 60 degrees, so it doesn't make sense to initialize such an object from three custom angles.
The same comment about the base class __init__
applies:
class Equilateral(Triangle):
angle = 60
def __init__(self):
super(Equilateral, self).__init__(Equilateral.angle,
Equilateral.angle,
Equilateral.angle)
Also note that there is no point in initializing Triangle
from three sides if you are talking about a space where the interior angles of a triangle are up to 180 degrees (or any fixed number). It would be more appropriate to transfer only two angles.
source to share
Both implementations seem to be slightly disabled. In Python, the superclass __init__()
is not automatically called . You must explicitly do this.
Shouldn't this just be inherited like in the code above with the Equilateral subclass?
When instantiated Equilateral
, Triangle.__init__()
never called in the above implementation. There is no automatic initializer inheritance (this would violate PEP 20 : "Explicit is better than implicit").
Equilateral
it's probably better to read:
class Equilateral(Triangle):
angle = 60
def __init__(self):
super(Equilateral, self).__init__(self.angle, self.angle, self.angle)
Same with ElectricCar
:
class ElectricCar(Car):
def __init__(self, model, color, mpg, battery_type):
super(ElectricCar, self).__init__(model, color, mpg)
self.battery_type = battery_type
I don't understand why they were written differently.
This question is difficult to answer. The author either misunderstood how Python inheritance works, or he / she had a clear reason for not calling the superclass initializer.
source to share
In Python, classes work like a bow. The outermost layer - this "instance" object self
. The layer below is a class object, itself is an instance. The layers below are class objects that are inherited from (base classes).
Put something in a class definition like number_of_sides
in Triangle
, puts something in a class object. The assignment self
puts something on an instance object, another onion layer.
When resolving the type name self.angle
, Python starts looking for the layer self
. If it isn't found there, it looks at the layer below, and so on. In the example, Equilatoral is angle
not found in self
, but it is in the class Equilatoral
. angle1
known only in an instance variable self
, not in a class variable Equilatoral
.
In the Car example, variables model
, color
and mpg
are stored in the instance, not in the class itself. They are created when a function is called Car.__init__
that is not inherited by any magic code. This is by design, as Python prefers explicitly hidden behavior. As juan explains, you must explicitly call the base class constructor to fully initialize the instance object.
At first, having to explicitly call basic constructors seems cumbersome, but in languages ββthat prefer implicit actions (like C ++ and its derivatives), you need all sorts of syntax nightmares to override implicit behavior explicitly. This is one of the reasons why Python has such a soft learning curve.
source to share