Creature Lab — Classes & objects
Six specimens built from scratch — blueprint first, then spawn from it.
How to play
Each level gives you a specification: expressions on the left, the value each should produce on the right. Write the class, press Run, and every row is ticked individually — so a class that works for one creature and quietly shares state between two tells you exactly which case broke.
What each level teaches
- The blueprint —
class,__init__andself. - Teach it a trick — methods, and how they reach their own data.
- Take a hit — changing an object's state rather than returning a new one.
- Make it printable —
__str__, instead of<__main__.Creature object at 0x7f…>. - Count the specimens — a class attribute, shared by every instance.
- Are they the same? —
__eq__, and what==means by default.
What self actually is
It is not a keyword and there is nothing magic about the name. When you call sparky.describe(),
Python calls Creature.describe(sparky) — the object is passed in as the first argument, and
self is just the conventional name for it. That is why every method needs it in the signature, and why
forgetting it gives you "takes 0 positional arguments but 1 was given", which is one of the most confusing
error messages a beginner meets.
The trap in level 5
Level 1 already checks that two creatures have independent hp, and level 5 is the mirror image:
self.count = …creates an attribute on that one object. Every creature gets its own, so the total is always 1.Creature.count = …changes the attribute on the class, which every instance shares.
Reading is the confusing part: self.count reads the class attribute perfectly well if no
instance attribute exists. So the count appears to work until something writes to it through self, and
from that moment the two silently diverge.
Dunder methods are hooks, not decoration
__str__ and __eq__ are not special-cased by the language — they are how Python asks
your object a question. print(x) calls __str__, x == y calls
__eq__, len(x) calls __len__, for i in x calls
__iter__. Implement the hook and your class works with the ordinary syntax everyone already knows. The
written version, including properties and dataclasses, is in the tutorial on
Python classes and objects.
Frequently asked questions
What is self in Python?
The instance the method was called on, passed in as the first argument. sparky.describe() is really Creature.describe(sparky). The name is convention, not a keyword.
What is the difference between a class attribute and an instance attribute?
A class attribute is defined in the class body and shared by every instance. An instance attribute is set through self, usually in __init__, and belongs to that one object.
What does __init__ do?
It runs immediately after an object is created, and is where you store the values that object needs. It is not a constructor in the strict sense — the object already exists by then.
Why does printing my object show something like <__main__.Dog object at 0x7f…>?
Because the class has no __str__. Define one returning readable text and print() will use it.
What is the difference between == and is?
== asks whether two things are equal, and calls __eq__ if you defined one. is asks whether they are the very same object in memory. Without __eq__, == falls back to is.
Keep going
- Read the classes & objects tutorial — the written explanation behind every level here.
- Variable Vault — variables & data types.
- Operator Arcade — numbers & operators.
- String Surgeon — strings & slicing.
- 20 Python practice exercises with worked solutions.
Take the games with you
Coding Python packs a real Python 3 compiler, 30 example programs, 112 quiz questions and 12 self-checking challenges into one free Android app.
Get it on Google Play