Intuition The one core idea
When you write x.speak(), Python does not ask "what type is x?" — it asks "does x have a thing called speak I can run?" and runs it. Everything about polymorphism and duck typing falls out of that single question, so the whole game is understanding what happens between the dot . and the parentheses ().
Before you can feel why "same interface, different behavior" works, you need to own every small piece of notation the parent note throws at you. We build them one at a time, from nothing, each one earning its place before the next arrives.
An object is a bundle: some data (values it remembers) plus some behaviors (things it can do). Think of it as a labelled box that carries both its stuff and the instructions for using that stuff.
Look at the figure. A Dog object is one box. Inside it: a spot for data, and a spot listing what it knows how to do (speak). A Cat is a different box with the same-named slot speak, but the instructions inside are different.
Intuition Why the topic needs this
Polymorphism is about many boxes responding to one command . You cannot talk about "different objects, same call" until "object" itself is a concrete picture: a box that knows how to do things.
A class is the template (rubber stamp) that stamps out objects. class Dog: describes what every dog box will contain; Dog() presses the stamp once and hands you a fresh box (an instance ).
The parentheses () after Dog mean "press the stamp now, make me one." Without them, Dog is just the stamp sitting on the desk.
Intuition Why the topic needs this
Duck typing says "the class name doesn't matter." You can only appreciate that once you know the class name is the label on the stamp — the thing Python is deliberately choosing to ignore.
Definition Attribute access (the dot)
Writing x.name means: go to the object x, look for a slot called name inside it, hand me what's there. The . is the reaching-in operation. A slot can hold data (a number) or a behavior (a method).
In the figure, dog.speak reaches into the dog box and finds the speak slot. What comes out is a thing you can run .
Intuition Why the topic needs this
The parent note says "method lookup is dynamic." The lookup is this reaching-in. Every polymorphism example is the dot doing its search.
Definition Method vs. method call
A method is a behavior stored in a slot (dog.speak — the recipe). Adding () runs it (dog.speak() — cook the recipe now). The bare name is the noun; the parentheses turn it into a verb.
Common mistake The single most common beginner slip
dog.speak (no parens) hands you the recipe object itself , not the result. dog.speak() runs it and hands you "Woof". Forgetting () is why people see <bound method ...> printed instead of the word they expected.
Intuition Why the topic needs this
"Same interface, different behavior" is exactly: the four-part shape x.speak() stays identical on the page, but which recipe the third part points to depends on which box x is. Break the anatomy apart and the whole idea becomes obvious.
Inside a method, self is the box the method was called on . When you run dog.speak(), Python secretly passes the dog box in as self, so the recipe can read that specific dog's own data.
Intuition Why the topic needs this
def speak(self): return "Woof" — the self in the definition is the receiving box. This is why two objects from the same class can behave differently based on their own remembered data. It's the wire connecting "which box" to "the recipe running."
Definition Exception / raise
An exception is Python's way of shouting "something went wrong here, stop." raise is you throwing that shout on purpose. AttributeError is the specific shout for "you asked for a slot that doesn't exist in this box."
The figure shows the fork: the dot searches for speak; if the slot exists → run it; if it's missing → AttributeError is raised.
Intuition Why the topic needs this
The parent's rule "if not found → AttributeError" is the failure branch of duck typing. NotImplementedError (in the base-class flavor) is a raise used to say "a real subclass must fill this in." You can't read those examples without knowing what a raised exception is.
Definition Interface (implicit)
An interface is just "the set of methods/attributes a piece of code uses." If total_area(shapes) only ever calls s.area(), then the interface it demands is simply: has a slot named area you can run. Nothing more.
Intuition Why the topic needs this
This is the whole punchline of duck typing: Python never writes the interface down anywhere; it's whatever slots your code happens to reach for . "If it walks like a duck…" means: if the box has the slots I use, I don't care what stamp made it.
Definition Method Resolution Order (MRO)
When one class is built on top of another (Dog(Animal)), a slot might live in the child, or up in the parent. The MRO is the ordered list Python walks — child first, then parents — looking for the slot. First match wins.
Intuition Why the topic needs this
The parent note's formula literally reads type(x).__mro__. Overriding (Mistake C) only makes sense once you see the dot walks this list and stops at the first hit — so a child's speak shadows the parent's without erasing it. Full detail lives in Method Resolution Order (MRO) .
object = box with data plus behaviors
class = stamp that makes boxes
dot = reach into a box for a slot
method plus parens = run the behavior
self = the box the method runs on
exception and raise = it cannot do that
interface = the set of slots code uses
MRO = search order across inherited boxes
POLYMORPHISM = one call, many behaviors
Read it top to bottom: boxes and stamps come first, the dot and the call sit in the middle, and the interface plus the failure-signal plus the search order all feed the one idea at the bottom.
Test yourself — cover the right side and answer out loud before revealing.
What is an object, in one picture? A labelled box holding both data and behaviors (instructions).
What does a class do, and what does Dog() return? The class is a stamp/template; Dog() presses it once and returns one instance (box).
In x.speak, what does the dot . do? Reaches into box x and looks for a slot named speak.
What's the difference between x.speak and x.speak()? x.speak hands you the recipe object; x.speak() runs it and hands you the result.
What is self inside a method? The specific box the method was called on, passed in automatically.
What does Python raise when you access a missing slot? AttributeError — "no such attribute on this object."
What does "interface" mean in duck typing? The set of methods/attributes the code actually uses — nothing formally declared.
What does the MRO decide? The order Python searches child-then-parent classes for a slot; first match wins.
State the one core idea in a sentence. Python asks "does x have this method?" not "what type is x?" — so any box with the right slots plugs in.