Consider this code: dog1 = Dog('Rex', 5); dog2 = Dog('Luna', 3); dog1.age = 10. After these three lines run, what is dog2.age?
A10, because dog1 and dog2 are instances of the same class and share attribute values
B3, because each instance maintains its own independent copy of its instance attributes
CNone, because the age attribute was modified and no longer has a valid value
D5, because dog2 was created before dog1's age was changed
Each instance occupies separate memory and owns its own copy of instance attributes. Modifying dog1.age = 10 changes only the slot in dog1's memory — dog2 has an entirely separate age slot that remains 3. This is the core concept: instances are like two houses built from the same blueprint — painting one house does not change the other's color. The most common misconception (option A) treats instances as sharing a single set of values, which would make OOP far less useful.
Question 2 Multiple Choice
A student writes 'dog1.__init__("Rex", 5)' to manually set up a dog object's attributes after creating it. Why is this the wrong approach?
ABecause __init__ does not accept arguments in Python
BBecause __init__ is called automatically when you instantiate the class — calling it explicitly would run initialization twice and bypasses the intended creation pattern
CBecause constructors can only be invoked by the Python interpreter, never directly by user code
DBecause you must use the Dog() syntax and cannot call __init__ with dot notation
When you write dog1 = Dog('Rex', 5), Python automatically calls __init__(self, 'Rex', 5) on the newly created object. You do not need to call __init__ again — and doing so would run the initialization logic a second time on an already-initialized object. The constructor's purpose is to set up the object the moment it comes into existence, triggered by instantiation. Calling __init__ manually after the fact is like using a house blueprint to redecorate a house that's already been fully built.
Question 3 True / False
All instances of the same class share the class's method definitions, but each instance has its own independent copy of its instance attributes.
TTrue
FFalse
Answer: True
Method definitions (like bark, fetch, __init__) live in the class itself — there is one copy shared by all instances, which is efficient. When you call my_dog.bark(), Python looks up bark in the Dog class and runs it with self = my_dog. But instance attributes (name, age) are stored in each instance's own memory. This design — shared behavior, independent data — is what makes object-oriented programming powerful: the same code operates on each object's specific state.
Question 4 True / False
When you call a method on an object (e.g., my_dog.bark()), Python stores a separate copy of the bark method in the instance's memory for each invocation.
TTrue
FFalse
Answer: False
Methods are stored once in the class definition and looked up there at call time — no copy is made in the instance's memory. Python passes the instance as the implicit first argument (self), allowing the method to access that instance's attributes. This lookup-at-call-time behavior is part of Python's descriptor protocol. Storing methods in each instance would waste memory and defeat the purpose of class-based organization. Only instance attributes (set via self.x = ...) are stored in the instance's own namespace.
Question 5 Short Answer
What is the difference between a class and an instance, and why does this distinction matter when you modify an attribute on one instance?
Think about your answer, then reveal below.
Model answer: A class is the blueprint — it defines the structure (what attributes objects will have) and the shared behavior (method definitions). An instance is a concrete object created from that blueprint, holding its own memory with its own attribute values. Because instances own their data independently, modifying dog1.age only changes that specific object's age slot in memory; dog2 has a completely separate age slot that is unaffected. The class is shared; the data is not. This independence is what allows multiple objects to represent distinct real-world entities even though they were built from the same template.
The class/instance distinction is foundational to all object-oriented design. As programs grow more complex — a Veterinarian examining a Dog, a Kennel holding a list of Dogs — each object needs to maintain its own state independently. If instances shared attribute values, you could not model multiple distinct dogs (or patients, or bank accounts) simultaneously. The blueprint/house analogy captures this: one blueprint, many independent houses.