Problem overview
The lesson asks for three classes. Shipping is the standard option, and Express and Economy inherit from it. Every option answers the same two questions: name() returns its name, and cost(weight) returns the price of a parcel of that many kilograms.
Shipping: the name is"Standard"and the cost is5 + weight.Express: the name is"Express"and the cost is10 + 2 * weight.Economy: the name is"Economy"and the cost is3 + weight // 2, with the division rounding down.
For a parcel of 4 kilograms the three options cost 9, 18 and 5.
Approach: one parent, two overrides
The code that uses these classes calls name() and cost(weight) on an option without knowing which kind it holds. That works because every option has both methods. Express and Economy write class Express(Shipping):, which makes them subclasses of Shipping, and each defines methods with the same names as the parent's. This is called overriding.
When you call a method on an object, Python looks for it in the object's own class first and only then in the parent. An Express object finds Express.cost straight away, so the parent's version never runs for it. Each class overrides only for itself: changing Express has no effect on Economy or Shipping.
Step by step
- Write
Shipping.nameso it returns the text"Standard". - Write
Shipping.costso it returns5 + weight: a base price plus 1 for each kilogram. - Override
nameinExpresswith the same header and the text"Express". - Override
costinExpress:10 + 2 * weight. If you left this out, an express parcel would silently get the parent's price. - Override
nameinEconomywith"Economy". - Override
costinEconomywith3 + weight // 2. The//operator divides and drops the remainder.
The solution in Python
class Shipping:
def name(self):
return "Standard"
def cost(self, weight):
return 5 + weight
class Express(Shipping):
def name(self):
return "Express"
def cost(self, weight):
return 10 + 2 * weight
class Economy(Shipping):
def name(self):
return "Economy"
def cost(self, weight):
return 3 + weight // 2
Here is the same parcel of 4 kilograms sent through each option:
for option in (Shipping(), Express(), Economy()):
print(f"{option.name()}: {option.cost(4)}")
Standard: 9
Express: 18
Economy: 5
The loop body is identical for all three objects, yet each one answers with its own version of the methods.
Why // and not /
In Python, / always gives a float and // gives the rounded-down result. With a weight of 7, 7 / 2 is 3.5 and 7 // 2 is 3. The lesson wants a whole price, so Economy's cost for 7 kilograms is 3 + 3 = 6. With / the method would return 6.5.
Edge cases and common mistakes
- Weight 0. Only the base prices are left: 5 for Standard, 10 for Express and 3 for Economy. Economy's
0 // 2is 0, so the formula needs no special case. - Weight 1 on Economy.
1 // 2is 0, so the cost is 3, the same as for an empty parcel. - Overriding only one method. A subclass that defines
costbut notnameinherits the parent'sname, so it would call itself"Standard". Override both. - Misspelling a method name. A method called
Nameorcostsis a new method, not an override, and the parent's version runs instead. The names and parameters must match the parent's. - Forgetting
self. Every method in a class takesselfas its first parameter, includingcost(self, weight). - Forgetting the parent in the class line.
class Express:makes an unrelated class. Writeclass Express(Shipping):.
Key takeaways
- A subclass overrides a method by defining one with the same name in its own class.
- Python runs the version belonging to the object's own class, so code written for the parent works with every subclass.
- Use
//when the result must be a whole number rounded down.
