Methods in a class
In the previous module, a Room worked out its area in the constructor and kept it in an attribute. That number is right when the room is made, and wrong as soon as the room changes:
class Room:
def __init__(self, name, width, length):
self.name = name
self.width = width
self.length = length
self.area = width * length
kitchen = Room("Kitchen", 3, 4)
kitchen.width = 5
print(kitchen.width, kitchen.length, kitchen.area)
5 4 12A room 5 meters by 4 isn't 12 square meters. The area shouldn't be stored at all: it should be worked out when someone asks for it, from the width and the length the room has at that moment. That's a job for a method, a function that is part of the class and works with the attributes of the object it is called on.
A method is defined inside the class, as the constructor is, and its first parameter is self, the object it is called on:
class Room:
def __init__(self, name, width, length):
self.name = name
self.width = width
self.length = length
def area(self):
return self.width * self.length
def describe(self):
return f"{self.name}: {self.area()} square meters"
kitchen = Room("Kitchen", 3, 4)
print(kitchen.area())
kitchen.width = 5
print(kitchen.area())
print(kitchen.describe())
12
20
Kitchen: 20 square meters- The methods are indented inside the class, with one blank line between them.
- When you call
kitchen.area(), Python passeskitchento the method asself, soself.widthinside the method is the kitchen's width. areaworks out the area from the attributes as they are when it is called. So, unlike an area stored in the constructor, it is never out of date: after the width changes, the next call gives the new area.- A method can call another method of the same object through
self:describecallsself.area().
Methods with parameters
A method can take arguments after self, as any function can:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def sale_price(self, percent):
return self.price * (100 - percent) / 100
lamp = Product("Desk lamp", 40)
print(lamp.sale_price(25))
print(lamp.sale_price(10))
30.0
36.0lamp.sale_price(25) has one argument in the parentheses, and inside the method self is the lamp and percent is 25.
Forgetting self
Every method needs self as its first parameter. Leave it out, and the call fails, because Python always passes the object:
class Room:
def __init__(self, width, length):
self.width = width
self.length = length
def area():
return self.width * self.length
hall = Room(2, 6)
print(hall.area())
Traceback (most recent call last):
File "main.py", line 11, in <module>
print(hall.area())
~~~~~~~~~^^
TypeError: Room.area() takes 0 positional arguments but 1 was givenThe "1 given" is the object itself. Inside a method, the attributes also need self. in front: a plain width is a NameError, and Python's message asks "Did you mean: 'self.width'?"