-
-
Notifications
You must be signed in to change notification settings - Fork 525
/
inheritance.py
140 lines (104 loc) · 5.19 KB
/
inheritance.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"""
Inheritance is a way to reuse code and data from a parent class. This
allows us to avoid repeating ourselves and to build upon existing
functionality. This module defines a basic vehicle class, creates a car
class that inherits from vehicle, then creates a truck class that
inherits from car and use it for demonstration purposes.
"""
from inspect import isfunction, ismethod
class Vehicle:
"""Basic definition of a vehicle.
We begin with a simple mental model of what a vehicle is. It has
a make, model, year, and miles. That way, we can start exploring
the core concepts that are associated with a class definition.
"""
def __init__(self, make, model, year, miles):
"""Construct a vehicle with make, model, year, and miles."""
self.make = make
self.model = model
self.year = year
self.miles = miles
def __repr__(self):
"""Return the formal representation of a vehicle."""
return f"<Vehicle make={self.make} model={self.model} year={self.year}>"
def __str__(self):
"""Return the informal representation of a vehicle."""
return f"{self.make} {self.model} ({self.year})"
def drive(self, rate_in_mph):
"""Drive a vehicle at a certain rate in MPH."""
return f"{self} is driving at {rate_in_mph} MPH"
class Car(Vehicle):
"""Definition of a car.
We inherit from the vehicle class to reuse the code and data that
we have already defined. In addition, we add a new attribute called
`wheels` to the car class. This is an example of extending the
functionality of a parent class. In __init__, we call the parent
constructor with the `super` function. This is a way to invoke the
parent constructor without having to explicitly name the parent
class. We also override the method `__repr__` to have a different
output than the vehicle.
"""
def __init__(self, make, model, year, miles):
"""Construct a car with make, model, year, miles, and wheels."""
super().__init__(make, model, year, miles)
self.wheels = 4
def __repr__(self):
"""Return the formal representation of a car."""
return f"<Car make={self.make} model={self.model} year={self.year} wheels={self.wheels}>"
class Truck(Vehicle):
"""Definition of a truck.
We inherit from vehicle just like we did with the car class. In this case we
will also override the method `drive` to have a different output than the
car and the vehicle.
"""
def __init__(self, make, model, year, miles):
"""Construct a truck with make, model, year, miles, and wheels."""
super().__init__(make, model, year, miles)
self.wheels = 6
def __repr__(self):
"""Return the formal representation of a truck."""
return f"<Truck make={self.make} model={self.model} year={self.year} wheels={self.wheels}>"
def drive(self, rate_in_mph):
"""Drive a truck at a certain rate in MPH."""
return f"{self} is driving a truck at {rate_in_mph} MPH"
def main():
# Create a vehicle with the provided class constructor
vehicle = Vehicle("Mistery Machine", "Van", 1969, 100000.0)
# Formal representation
assert repr(vehicle) == "<Vehicle make=Mistery Machine model=Van year=1969>"
# Informal representation
assert str(vehicle) == "Mistery Machine Van (1969)"
# Call a method on the class constructor
assert vehicle.drive(50) == "Mistery Machine Van (1969) is driving at 50 MPH"
# Check the type of the method drive
assert ismethod(vehicle.drive) and not isfunction(vehicle.drive)
# Now we create a car with the provided class constructor
car = Car("DeLorean", "DMC-12", 1982, 220000.0)
# The informal representation is similar to the vehicle
assert str(car) == "DeLorean DMC-12 (1982)"
# But the formal representation is different because we included
# the wheels attribute
assert repr(car) == "<Car make=DeLorean model=DMC-12 year=1982 wheels=4>"
# And we can check the type of the method drive like we did with
# the vehicle
assert ismethod(car.drive) and not isfunction(car.drive)
# If we call the method drive, we can see that we did not
# write any code for the car class, but we can still use it
# because it is inherited from the vehicle class and the
# behavior is the same as the vehicle
assert car.drive(50) == "DeLorean DMC-12 (1982) is driving at 50 MPH"
# Now we create a truck with the provided class constructor
truck = Truck("Optimus Prime", "Truck", 1984, 1000000.0)
# Like car and vehicle, the informal representation is similar
assert str(truck) == "Optimus Prime Truck (1984)"
# And the formal representation is different from the vehicle
# because we included the wheels attribute
assert repr(truck) == "<Truck make=Optimus Prime model=Truck year=1984 wheels=6>"
# And we can check the type of the method drive like we did with
# the vehicle
assert ismethod(truck.drive) and not isfunction(truck.drive)
# For the last part, we can see that the method drive is different
# for the truck
assert truck.drive(50) == "Optimus Prime Truck (1984) is driving a truck at 50 MPH"
if __name__ == "__main__":
main()