Learning Goals
3 minBy the end of this lesson you can:
- Tell the difference between a class (the blueprint) and an instance (a thing built from it).
- Define an empty class with the
classkeyword. - Make one or more instances by calling the class like a function.
- Recognise that every value in Python is already an instance of some class.
Warm-Up · Everything Is Already an Object
5 minType these three lines and predict what each prints:
print(type(42)) print(type("hello")) print(type([1, 2, 3]))
Show the answer
<class 'int'> <class 'str'> <class 'list'>
Every value Python knows about belongs to a class — int, str, list. Even print itself is an instance of a class (builtin_function_or_method). The whole language is built on this idea; today we're just learning the words for it.
A class describes a kind of thing. An instance is one particular thing of that kind. Python comes with dozens of classes (int, str, list, dict...) — and today you learn how to make your own.
New Concept · class, Instance, type()
14 minThe smallest possible class
Use the keyword class, give it a name (PascalCase by convention — first letter of each word capitalised), and write pass in the body for now.
class Hero: pass
That's a complete, valid class. It does nothing useful — no data, no behaviour — but it exists.
Making instances
Call the class name like a function. Each call makes a new, independent instance.
class Hero: pass aisyah = Hero() wei_jie = Hero() print(aisyah) print(wei_jie) print(aisyah is wei_jie) # → False (different instances)
<__main__.Hero object at 0x7f8b...> <__main__.Hero object at 0x7f8b...> False
Two heroes, two memory addresses. is tests whether two variables point to the same object — these don't.
What just happened?
Look at the picture:
class Hero
(blueprint)
┌────────────┐
│ │
└─────┬──────┘
│ calling Hero() makes...
┌──────┴───────┐
↓ ↓
aisyah = Hero() wei_jie = Hero()
(instance #1) (instance #2)One class. Many instances. Each instance is its own thing in memory, but they all follow the same blueprint.
type() and isinstance()
Two functions to inspect:
print(type(aisyah)) # → <class '__main__.Hero'> print(isinstance(aisyah, Hero)) # → True print(isinstance(42, int)) # → True print(isinstance("hi", Hero)) # → False
isinstance(x, ClassName) is how you ask "is this thing one of these?". Prefer it over type(x) == ClassName — works better when you add inheritance later.
Why bother?
Right now Hero() does nothing. The point of classes only becomes clear once we add attributes (tomorrow) and methods (the day after). The pattern then becomes:
Each instance carries its OWN data. All instances share the SAME behaviour.
Five different heroes can have five different names and HP values — but they all fight the same way, because the fight code lives in the class. That separation is what makes OOP powerful.
Worked Example · Three Empty Heroes
12 minSave as heroes.py:
# heroes.py — first taste of classes class Hero: pass # Make three instances hero_a = Hero() hero_b = Hero() hero_c = Hero() # Each is its own object print(hero_a) print(hero_b) print(hero_c) # But they're all heroes print(isinstance(hero_a, Hero)) print(isinstance(hero_b, Hero)) print(isinstance(hero_c, Hero)) # Store them in a list — they fit alongside anything else heroes = [hero_a, hero_b, hero_c] print(f"\n{len(heroes)} heroes ready for adventure.") for h in heroes: print(f" - {h}")
Sample output (addresses will vary)
<__main__.Hero object at 0x10a3c1d50> <__main__.Hero object at 0x10a3c1d90> <__main__.Hero object at 0x10a3c1dd0> True True True 3 heroes ready for adventure. - <__main__.Hero object at 0x10a3c1d50> - <__main__.Hero object at 0x10a3c1d90> - <__main__.Hero object at 0x10a3c1dd0>
Read the diff
Three instances. Three different memory addresses. They're "empty" — no data attached yet — but they're real Python objects you can pass around, store in lists, compare with isinstance. Tomorrow we'll fill them with data; the day after they'll do things.
The default print output (<__main__.Hero object at 0x...>) is unhelpful. There's a special method called __str__ that controls what gets printed — we'll meet it in PY-L3-14. For now the ugly default is fine.
Try It Yourself
13 minDefine two classes — Pet and Toy. Create one instance of each. Use isinstance to confirm each is the right kind.
Hint
class Pet: pass class Toy: pass fluffy = Pet() ball = Toy() print(isinstance(fluffy, Pet)) # → True print(isinstance(fluffy, Toy)) # → False print(isinstance(ball, Toy)) # → True
Notice that fluffy is a Pet but not a Toy — even though both classes are empty. Class identity matters, not contents.
Make two Pet instances. Compare them with == and is. Predict the answers before printing.
Hint
class Pet: pass a = Pet() b = Pet() c = a # NOT a new instance — same object as a print(a == b) # → False (default == for objects = identity) print(a is b) # → False print(a == c) # → True print(a is c) # → True (same memory)
== for plain classes defaults to comparing identity (same object?). We'll meet __eq__ in PY-L3-15 to customise this.
Get the class of [1, 2, 3] using type(). Then use that class as a constructor to make a brand-new empty list. Confirm both are lists.
Hint
numbers = [1, 2, 3] ListClass = type(numbers) empty_list = ListClass() # same as list() print(empty_list) # → [] print(isinstance(empty_list, list)) # → True
Classes are first-class values in Python — you can store them in variables and call them. type(x) returns the class; list is just a name for the same class.
Mini-Challenge · The Type Zoo
8 minBuild zoo.py. Define four empty classes — Mammal, Bird, Reptile, Fish. Create three instances of each — six creatures total. Store them all in one big list creatures.
Then loop the list and print, for each creature, what kind it is. Use type(c).__name__ to get the class name as a string.
Finally, count and print how many of each kind there are.
Show one possible solution
# zoo.py — count creatures by kind class Mammal: pass class Bird: pass class Reptile: pass class Fish: pass creatures = [ Mammal(), Mammal(), Bird(), Bird(), Bird(), Reptile(), Fish(), Fish(), Fish(), Fish(), ] # Print every creature with its kind for c in creatures: print(f" {type(c).__name__}") # Count by kind counts = {} for c in creatures: name = type(c).__name__ counts[name] = counts.get(name, 0) + 1 print() for kind, n in counts.items(): print(f" {kind:<10} {n}")
Non-negotiables: four empty classes, a mixed list of instances, type(c).__name__ for the kind, and a dict to count. type(c).__name__ is the cleanest way to ask "what class is this?" as a string.
Recap
3 minA class is a blueprint for a kind of thing. The keyword class defines one — even an empty one with just pass is valid. An instance is one specific object built from that blueprint; you make one by calling the class like a function (Hero()). Every value in Python is already an instance of some class — int, str, list, etc. type(x) and isinstance(x, ClassName) tell you what kind of thing x is. We'll spend the next few lessons giving classes data and behaviour.
Vocabulary Card
- class
- A blueprint for a kind of object. Defined with the
classkeyword. - instance
- One specific object built from a class. Made by calling the class like a function.
- type(x)
- Returns the class of
x. - isinstance(x, C)
- Returns
Trueifxis an instance of classC(or a child class). - PascalCase
- The convention for class names — capital first letter of every word, no underscores.
Hero,BankAccount,HttpClient.
Homework
4 minSave my_classes.py. Define three empty classes named after things you care about — for example Book, Song, Player. For each one:
- Create three instances.
- Print each instance and its
type(...).__name__. - Confirm with
isinstance(...)that each instance is the correct class.
End with a final printed message like 9 objects across 3 classes.
Sample · my_classes.py
# my_classes.py — three classes, nine instances class Book: pass class Song: pass class Player: pass books = [Book(), Book(), Book()] songs = [Song(), Song(), Song()] players = [Player(), Player(), Player()] for collection in (books, songs, players): for thing in collection: kind = type(thing).__name__ print(f" {thing} ({kind})") assert isinstance(thing, type(thing)) total = len(books) + len(songs) + len(players) print(f"\n{total} objects across 3 classes")
Non-negotiables: three classes, three instances each, isinstance checks, a count summary. assert is a quick way to confirm a condition without writing print statements — it crashes if the condition is False.