Objects and Classes
An object bundles state and behavior together, with its own identity — a class is the blueprint that objects are built from.
By the end of this lesson, you can
- Describe an object as a bundle of state (attributes) and behavior (methods)
- Write a small class with __init__ and a method, and create more than one independent instance
- Explain why each instance keeps its own separate state, even though every instance shares the same class
Why it matters
A library holds many books, and each one needs to be tracked separately: its own title, its own loan status. Tracking this with loose variables works for one book, but falls apart with more than one — which variable belongs to which book? An object solves this by bundling related state and behavior together under one name, so each book can be handled as a single thing with its own identity.
Mental model
Before any Python syntax, think about a library book directly:
- It has state: a title, and whether it’s currently on loan.
- It has behavior: it can be borrowed.
- It has identity: two copies of the same title on a shelf are still two separate books — borrowing one doesn’t affect the other.
An object is exactly this: state and behavior bundled together, with its own identity. A class is the blueprint that says what every book object will have; each individual book built from it is called an instance.
Small example
class LibraryBook:
def __init__(self, title):
self.title = title
self.is_on_loan = False
def borrow(self):
if self.is_on_loan:
return False
self.is_on_loan = True
return True
book1 = LibraryBook("Dune")
book2 = LibraryBook("Foundation")
print(book1.borrow())
print(book2.is_on_loan)True
False__init__ is a special method that runs once, when a new object is
created — it’s where an object’s starting attributes (title,
is_on_loan) get set. self refers to this particular object:
inside borrow, self.is_on_loan means “the is_on_loan attribute of
whichever book this method was called on” — not every book.
Trace it
| Step | book1.title | book1.is_on_loan | book2.title | book2.is_on_loan |
|---|---|---|---|---|
| after creation | Dune | False | Foundation | False |
| book1.borrow() | Dune | True | Foundation | False |
Calling book1.borrow() only changes book1’s attributes.
book2.is_on_loan is untouched — even though book1 and book2 were
built from the exact same class, using the exact same method.
Check your understanding
Or reveal the answer without checking
Answer:True, then False
The first borrow() sets is_on_loan to True and returns True. The second call sees is_on_loan is already True, so its if branch runs, returning False without changing anything.
Or reveal the answer without checking
Answer:Nothing — book2's state is completely independent of book1's
Each instance holds its own independent attributes. Calling a method on book1 can only ever change book1's state, regardless of what other instances of the same class exist.
Practice: warm-up
Trace this program by hand — write down is_on_loan for both books
after each line — before revealing the answer.
a = LibraryBook("Dune")
b = LibraryBook("Dune")
a.borrow()
b.borrow()
a.borrow()
Stuck? Reveal one hint at a time.
Hint 1
a and b are two separate instances, even though they have the same title — track them separately.
Hint 2
The third line calls borrow() on a again, while it is already on loan — what does borrow() do in that case?
Reveal the trace
Try the problem yourself before reading this. There is often more than one reasonable approach — treat this as one worked example, not the only correct answer.
a = LibraryBook("Dune") -> a.is_on_loan = False
b = LibraryBook("Dune") -> b.is_on_loan = False (independent of a)
a.borrow() -> a.is_on_loan = True, returns True
b.borrow() -> b.is_on_loan = True, returns True (independent of a)
a.borrow() -> a.is_on_loan stays True, returns False (already on loan)Practice: apply it
LibraryBook has no way to return a book once it’s borrowed.
Or reveal the answer without checking
Answer:Set self.is_on_loan to False
Returning a book should reverse exactly the state change borrow() made — is_on_loan back to False — so it can be borrowed again.
Modification challenge: add a return_book method to LibraryBook
that sets self.is_on_loan back to False, then trace a.borrow()
followed by a.return_book() followed by a.borrow() again to confirm
it can be borrowed a second time.
Summary
- An object bundles state (attributes) and behavior (methods) together under one identity.
- A class is the blueprint; each object built from it is an instance, with its own independent copies of the attributes
__init__sets up. selfinside a method refers to the specific instance the method was called on — never every instance of the class.- Sharing a class means sharing the blueprint, not the state — calling a method on one instance never affects another.