What you'll learn
- Explain what an object is and what a class is, in one sentence each
- See that every value you have used so far is already an object with methods
- Understand why programs are built from objects: data and behavior kept together
- Name the four pillars of OOP and what each one means in practice
Concept
You have been using objects since the first lesson. A string is an object: it holds data, the characters, and it carries behavior, methods like upper() and split(). A list is an object with append and sort. When you write name.upper(), you are asking the object to do something with its own data. Object-oriented programming is nothing more exotic than building your own kinds of objects, so that your data and the operations on it live together the way strings and lists already do.

A class is the blueprint; an object is one thing built from it. str is a class, and "hello" is an object of that class, also called an instance. type(x) tells you the class of any object. When you write your own class, class BankAccount:, you are defining a new type, and every account you then create is an instance with its own balance and the same set of operations. Two accounts share the class and differ in their data.
Why bother, when functions and dictionaries already work? Because a dictionary of account data plus a pile of functions that take dictionaries has no boundary: any code can reach in and set the balance to a string, and the functions that belong to accounts are scattered among everything else. A class draws the boundary. The data is inside, the operations are attached, and a reader can see in one place what an account is and what it can do.
| Without objects | With objects |
|---|---|
account = {"owner": "ada", "balance": 100} |
account = BankAccount("ada", 100) |
deposit(account, 50) |
account.deposit(50) |
anyone can write account["balance"] = "oops" |
the class decides how balance changes |
| functions for accounts live anywhere | they live in the class, next to the data |
The four pillars are the vocabulary you will hear in every interview and read in every codebase. Encapsulation: data and the operations on it live together, and the object controls how its data changes. Abstraction: you use an object through a small set of methods without knowing how it works inside, the way you use list.sort() without knowing the algorithm. Inheritance: a class can be built on another class, gaining its behavior and adding or changing some. Polymorphism: different classes can offer the same method, so code that calls .area() works on a circle and a square alike.

Everything in Python is an object, including functions, modules, and classes themselves. That is why help(len) works, why you can pass a function to sorted as a key, and why import math gives you something with attributes. You do not need to hold all of that in your head yet. You need only the mental model: an object is data plus behavior, a class describes a kind of object, and the next lessons teach you to write them.
Code
Objects you already know, inspected. Every value has a class, and every class defines the methods its objects can perform.
# already_objects.py
name = "hello"
items = [3, 1, 2]
number = 42
for value in (name, items, number, len, print):
print(f"{value!r:<26} is an instance of {type(value).__name__}")
print("upper" in dir(name), "append" in dir(items), "append" in dir(name))
'hello' is an instance of str
[3, 1, 2] is an instance of list
42 is an instance of int
<built-in function len> is an instance of builtin_function_or_method
<built-in function print> is an instance of builtin_function_or_method
True True FalseThe same idea two ways: a dictionary plus a function, then a class. Read the class as a preview of the next lesson, and notice how the operation and the data now travel together.
# two_ways.py
def deposit(account, amount):
account["balance"] += amount
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.balance = balance
def deposit(self, amount):
self.balance += amount
dict_account = {"owner": "ada", "balance": 100}
deposit(dict_account, 50)
print(dict_account)
obj_account = BankAccount("ada", 100)
obj_account.deposit(50)
print(obj_account.owner, obj_account.balance)
print(type(obj_account).__name__, isinstance(obj_account, BankAccount))
{'owner': 'ada', 'balance': 150}
ada 150
BankAccount TruePolymorphism in the built-ins, before you write any class. One loop calls len() and iterates over three different kinds of object, because all three support the same operations.
# polymorphic_builtin.py
things = ["abc", [1, 2, 3, 4], {"x": 1, "y": 2}]
for thing in things:
print(type(thing).__name__, len(thing), [item for item in thing])
str 3 ['a', 'b', 'c']
list 4 [1, 2, 3, 4]
dict 2 ['x', 'y']Try it yourself
Create inspect_objects.py. Make one value of each type you know (str, int, float, bool, list, tuple, dict, set) and, for each, print its class name and three of its method names from dir() that do not start with an underscore. Then write one sentence per value describing its data and one behavior, in a comment. You are describing objects; the next lesson shows you how to define them.
Common mistakes
- Thinking OOP is a separate mode of Python. Every value is already an object; classes let you add your own kinds.
- Confusing a class with an instance.
stris the class;"hello"is an instance.BankAccountis the class;BankAccount("ada", 100)is an instance. - Learning the pillars as definitions. They are habits you will recognize in code over the next seven lessons; the words matter less than the shape.
What's next
- An object is data plus the behavior that belongs to it; a class is the blueprint that defines a kind of object.
- Every Python value is already an object with a class; your own classes work the same way.
- Encapsulation, abstraction, inheritance, and polymorphism are the four pillars, each covered in its own lesson ahead.
You have the picture. Next you will write your first class, create instances from it, and give them their own state.