2.1.1 · D5OOP Fundamentals
Question bank — Class vs object — blueprint vs instance
A quick vocabulary refresher so every word here is earned:
Two more words appear throughout this bank, so we build them before we use them:
Before the trap bank, hold these two pictures in your head — the whole page rests on them.
Picture 1 — one blueprint, many independent instances, shared method:

Picture 2 — the trap-buster grid: the two questions crossed into four cases:

True or false — justify
TF1. Writing class Dog: ... creates a Dog object in memory.
False — it only records the blueprint; no object exists until you call
Dog(...). A drawing is not a house.TF2. Two objects built from the same class always share the same instance attributes.
False — they share the class's code and class attributes, but each gets its own copy of instance attributes via
self.x = ... (see the two separate data boxes in Picture 1).TF3. a = Dog("Rex", 3) and b = Dog("Rex", 3) refer to the same object.
False — each call to
Dog(...) builds a brand-new object in a new memory cell, so a is b is False even though their data matches.TF4. Changing a class attribute with Dog.species = "Lupus" changes it for every existing object.
True — objects that never set their own
species look up the class value (the single shared box in Picture 1), so the change is visible through all of them.TF5. Methods are stored separately inside each object.
False — methods live once on the class and are looked up when called; this is why
d1.bark() and d2.bark() run identical code on different data.TF6. If a == b is True, then a is b must also be True.
False —
== can compare values while is compares memory identity; two separate objects can be equal in value yet distinct in memory (the amber "value" cell of Picture 2).TF7. You can build 1000 objects from one class.
True — that is the whole point of a blueprint: describe once, instantiate as many independent instances as you like.
TF8. type(a) is Dog being True means a is the class Dog.
False — it means
a was built from Dog; a is an instance, the class is its template, and they are different kinds of thing.TF9. Assigning d1.age = 4 also alters d2.age.
False —
d1.age = 4 writes only into d1's own memory, so d2 keeps its independent age value.TF10. A class with no __init__ still lets you make objects.
True —
__init__ only fills in starting data; Python can still create the blank object, so you get an instance with no custom attributes set.Spot the error
SE1. "The name attribute is stored on the class because I typed it inside the class body."
The error:
self.name = name runs per object during instantiation, writing into that instance's own memory (self = this object) — the class only holds code and class attributes.SE2. "Dog and d1 = Dog(...) are the same thing, just spelled differently."
The error:
Dog is the blueprint (a class), d1 is a built instance; one describes, the other is a concrete object occupying memory.SE3. "I called Dog.bark() on the class and expected a woof."
The error:
bark needs a specific object supplied as self; calling it on the bare class gives it no instance to act on, so it fails or needs an object passed explicitly.SE4. "Since d1 and d2 are equal in every field, I used is to confirm they're equal."
The error:
is tests identity (same memory cell), not equality of values; use == (or compare fields) to check equal data.SE5. "I set d1.species = 'Lupus' to change the species for all dogs."
The error: assigning on the instance creates an instance attribute that shadows the class one for
d1 only; to change it for all, assign on the class (Dog.species = ...).SE6. "Defining the class already used up memory for all its future objects."
The error: the class costs only its own definition; each object's memory is allocated only when you instantiate it.
Why questions
WHY1. Why store methods on the class instead of copying them into every object?
To keep one shared copy of the behaviour code, so 1000 objects don't each waste memory storing 1000 identical method bodies.
WHY2. Why does each object need its own copy of instance attributes?
So objects have independent state — changing one object's data must never silently corrupt another's.
WHY3. Why split blueprint from instance at all?
For reuse (describe once, stamp many), independent state (each keeps its own data), and shared behaviour (methods stored once) — three benefits impossible if class and object were one thing.
WHY4. Why is is different from == if the objects look identical?
Because "same values" and "same physical object in memory" are genuinely different questions; two receipts can print the same total yet be two separate pieces of paper.
WHY5. Why does __init__ take self as its first parameter?
Because Python hands the freshly created blank object in as
self, so the constructor knows which object to write the data into.WHY6. Why can changing a class attribute surprise a beginner?
Because objects that never set their own copy transparently read the class value, so a single class-level edit ripples to all of them at once.
Edge cases
EC1. What happens if you never call the class, only define it?
Zero objects exist and zero instance memory is used; you have a plan and nothing built from it.
EC2. If an object sets its own species, then later Dog.species changes, what does that object see?
It keeps its own shadowing value — the instance attribute wins over the class one for that object, so the class change is invisible to it.
EC3. Can two variables point at the exact same object?
Yes —
b = a copies the reference, so a is b is True and edits through either name affect the one shared object.EC4. Is the class itself an object in memory?
Yes in Python — the class is also a runtime object (of a metaclass), which is why you can attach attributes to it like
Dog.species; but it is still the blueprint, not an instance of itself.EC5. What is the state of a freshly created object before __init__ writes anything?
A blank instance of the correct type with no instance attributes yet;
__init__ then fills in its data.EC6. If you delete d1, what happens to d2 built from the same class?
Nothing —
d2 is a separate object with its own memory, exactly like throwing away one cookie leaves the others intact.EC7. If a class attribute is a list (tags = []) and you do d1.tags.append("x") without ever reassigning, what happens to d2.tags?
Both are surprised —
d1.tags looks up the one shared list on the class and mutates it in place, so d2.tags now also shows ["x"]; no instance copy was ever made because you never assigned d1.tags = ....EC8. How is EC7 different from d1.tags = ["x"]?
Reassignment creates a fresh instance attribute that shadows the class list for
d1 only; mutation (.append) touches the shared object itself, so the trap is "mutate shared vs. reassign own" — a distinct trap from EC2's simple reassignment.Connections
- Class vs instance attributes — deepen the shared-vs-own data traps (TF2, TF4, SE5, EC2, EC7–EC8); it shows exactly when a lookup hits the class list versus an instance copy.
- Identity vs Equality (is vs ==) — the mechanics behind the
is/==traps (TF3, TF6, SE4) and why equal data ≠ same object. - Constructors and __init__ — full walkthrough of the
__init__setup step andselfbinding used in WHY5, EC5, and the EC7 fix. - self and instance methods — how
selfis supplied at call time, underpinning SE1 and SE3. - Memory model and references — the reference-copying behind EC3, EC6 and the shared-list mutation in EC7.
- Encapsulation — why bundling data and behaviour into one blueprint is worth all this care (WHY3).