A class is a blueprint; objects are built from it
Object-oriented programming (OOP) groups data and the functions that work on it into one unit.
- A class is a blueprint, such as the design of a bank account.
- An object (or *instance*) is one real thing made from that blueprint: Asha's account, Ravi's account.
- Attributes are an object's data (owner, balance).
- Methods are functions that belong to the class (deposit, withdraw).
You already use objects: every string is an object of class str, and "hi".upper() calls a method.
Writing your first class
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner # attribute
self.balance = balance # attribute
def deposit(self, amount): # method
self.balance += amount
def withdraw(self, amount):
if amount > self.balance:
print("Not enough balance")
else:
self.balance -= amount
a = BankAccount("Asha", 1000) # create an object
b = BankAccount("Ravi")
a.deposit(500)
print(a.owner, a.balance) # Asha 1500
print(b.balance) # 0
Class names use *CapitalWords* by convention.
__init__ and self
__init__is the constructor. It runs automatically each time you create an object, and sets up the object's starting attributes.selfis the object the method is working on. When you calla.deposit(500), Python passesaasself, soself.balancemeans *a's* balance.- Every method needs
selfas its first parameter, but you never pass it yourself.
What happens on a = BankAccount("Asha", 1000):
- Python makes a new, empty object.
- It calls
__init__(new_object, "Asha", 1000). __init__storesownerandbalanceon the object.- The finished object is stored in
a.
Methods that change and check object data
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks # a list of marks
def add_mark(self, m):
self.marks.append(m)
def average(self):
return sum(self.marks) / len(self.marks)
def passed(self):
return self.average() >= 33 # one method can call another through self
s = Student("Meena", [80, 72])
s.add_mark(90)
print(round(s.average(), 1), s.passed()) # 80.7 True
__str__ and __repr__: make objects print nicely
Printing an object normally shows something like <__main__.Student object at 0x0000...>. Define __str__ to control what print() shows:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self): # for users: print(), str()
return f"{self.name}: Rs {self.price}"
def __repr__(self): # for programmers: the shell, lists
return f"Product({self.name!r}, {self.price})"
p = Product("Pen", 10)
print(p) # Pen: Rs 10
print([p]) # [Product('Pen', 10)]
Class attributes and instance attributes
class Student:
school = "Model School" # class attribute: shared by all students
def __init__(self, name):
self.name = name # instance attribute: different for each
a, b = Student("Asha"), Student("Ravi")
print(a.school, b.school) # Model School Model School
Student.school = "City School" # changes it for everyone
Use class attributes for values every object shares, such as a GST rate or a school name.
Lists of objects
students = [Student("Asha"), Student("Ravi"), Student("Meena")]
for s in students:
print(s.name)
products = [Product("Pen", 10), Product("Bag", 450), Product("Book", 120)]
cheap = [p for p in products if p.price < 200]
products.sort(key=lambda p: p.price)
Example: library book
class Book:
def __init__(self, title):
self.title = title
self.issued_to = None
def issue(self, student):
if self.issued_to:
return f"Already issued to {self.issued_to}"
self.issued_to = student
return f"{self.title} issued to {student}"
def give_back(self):
self.issued_to = None
Common mistakes
- Forgetting
selfin a method definition:TypeError: ... takes 0 positional arguments but 1 was given. - Writing
balanceinstead ofself.balanceinside a method, which creates a local variable instead. - Misspelling the constructor as
__int__or_init_: it then never runs. - Calling a method without brackets:
a.depositnames the method;a.deposit(100)runs it.
Key points
- A class is a blueprint; each object has its own attributes.
__init__sets up a new object;selfis the object being used.__str__controls whatprint(obj)shows.- Class attributes are shared; instance attributes belong to one object.
Practice questions
1. Write a Rectangle class with length and width and an area() method.
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
print(Rectangle(4, 5).area()) # 202. What is self in a.deposit(500)?
The object a. Python passes it automatically as the first argument.
3. What does print(obj) show if the class has no __str__ or __repr__?
Something like <__main__.Rectangle object at 0x...>: the class name and a memory address.
4. A class has rate = 18 at class level. Is it shared by all objects?
Yes. It is a class attribute, so every object reads the same value until one object sets its own self.rate.
5. Add a __str__ to Rectangle that prints Rectangle 4 x 5.
def __str__(self):
return f"Rectangle {self.length} x {self.width}"