Lesson 1 of 8 in the Pre-COSMOS series, 41 slides, teaching objects through USE rather than through writing classes. The dot you have been typing all along - robot.look(), "hi".upper(), nums.append() - reaches inside an object, and an object bundles data, its attributes, which you read without parentheses, together with actions, its methods, which you call with parentheses. You work entirely with a Rover that is provided for you: reading .energy, .name, and .facing, calling .move() and .charge(amount), watching methods change the object's own state, and seeing that two rovers, Rex and Nova, keep their data separate. The three traps are the classic beginner errors: rover.move against rover.move(), rover.energy(), which gives 'int' object is not callable, and thinking that energy is shared between rovers. There are five checks and a scaffolded your-turn Drive the Rover build. Every snippet was run on CPython 3.12, with the outputs copied verbatim.
Subject: Python · 69 slides · code lesson
Open the interactive version of this deck · Homework for this lesson
Title
Pre-COSMOS · Lesson 1 of 8
You've typed the dot a hundred times - robot.look(), "hi".upper(), scores.append(7). Today you finally meet what's on the other side of it.
Objectives
An object is the big idea the rest of this camp is built on - so we start gently, using objects somebody already wrote. By the end you can:
rover.move().rover.energy.rover.charge(25).Warm-up
Discussion prompt
Before we open Objects, Part 1: What the Dot Means: without looking back, what was the main idea of NumPy as Grids: an Image is a Table of Numbers, and what could you do by the end of it that you could not do before?
Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.
Answer:
Pre-COSMOS Lesson 4 of 8 (37 slides): the one NumPy idea that powers camp vision - a 2D array is a grid, and a grayscale image is a grid of brightness numbers (0 dark .. 255 bright).
Concept
Figure (svg): A value on the left with a dot leading into a rounded box, showing that the dot reaches inside the thing on its left.
Every one of these has a dot, and on the left of the dot is an object:
"hello".upper() - the string is an object.scores.append(7) - the list is an object.robot.look() - the robot is an object.The dot has always meant the same thing: reach inside the object on my left. Today we name what's in there.
Counterexample
Discussion prompt
Every one of these has a dot, and on the left of the dot is an object:
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Answer:
The dot has always meant the same thing: reach inside the object on my left. Today we name what's in there.
Concept
Four stops, each one a piece of the same picture:
.move()..energy.Matching
Match the pairs
From Today's roadmap — match each one to what it actually does. The descriptions have been shuffled.
.move()..energy.Why: The dot, Methods, Attributes, A fleet are easy to tell apart while they are sitting next to their descriptions and much harder afterwards, which is what this checks.
Section
Section 1
Concept
An object bundles two things under one name: data (what it knows) and actions (what it can do). The dot is how you reach either one.
A Rover object knows its energy and its name, and it can move and charge. All of that lives inside the one rover.
Analogy
Discussion prompt
Explain What an object is by analogy to something with no Python in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
An object bundles two things under one name: data (what it knows) and actions (what it can do). The dot is how you reach either one.
Concept
object — A bundle of data and actions under one name. You reach into it with a dot.
attribute — A piece of data stored on the object - like a variable that belongs to it. Read it with NO parentheses: rover.energy.
method — An action the object can do - like a function that belongs to it. Call it WITH parentheses: rover.move().
Picture it
Figure (svg): A labeled backpack: a pocket holding energy 100 and name Rex (the attributes), and two buttons move and charge (the methods).
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Picture a backpack with your name on it. Inside are things you own (your data). On the straps are buttons that do something (your actions).
Intuition
Picture a backpack with your name on it. Inside are things you own (your data). On the straps are buttons that do something (your actions).
Figure (svg): A labeled backpack: a pocket holding energy 100 and name Rex (the attributes), and two buttons move and charge (the methods).
Reading the pocket is an attribute (rover.energy). Pressing a button is a method (rover.move()). The dot is your hand reaching in.
Explain it
Discussion prompt
Explain An object is a backpack to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Picture a backpack with your name on it. Inside are things you own (your data). On the straps are buttons that do something (your actions).
Worked example
Someone already wrote the Rover. You're handed one named Rex. Read what it knows - no parentheses on data.
rover = Rover("Rex")
print(rover.name)
print(rover.energy)
print(rover.facing)Each rover.something with no parentheses just reads a stored value.
| line | reads | prints |
|---|---|---|
| rover.name | the name attribute | Rex |
| rover.energy | the energy attribute | 100 |
| rover.facing | the facing attribute | north |
Comparison
Comparison matrix
From Meet Rex (a provided rover): refill the reads column from what you know. The rest of the table is as it appeared.
| line | reads | prints |
|---|---|---|
| rover.name | the name attribute | Rex |
| rover.energy | the energy attribute | 100 |
| rover.facing | the facing attribute | north |
Concept
This single distinction is the whole lesson:
(): rover.energy(): rover.move()The parentheses are the difference between looking at something and doing something.
Explain it
Discussion prompt
Explain The one rule: parentheses or not to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
The parentheses are the difference between looking at something and doing something.
Worked example
move() is an action, so it needs (). Each call rolls Rex forward and spends 10 energy.
rover = Rover("Rex")
rover.move()
rover.move()
rover.move()Watch energy drop by 10 each call - the object remembers the new value.
| call | prints | energy after |
|---|---|---|
| start | (nothing) | 100 |
| rover.move() | Rex rolls forward. Energy: 90 | 90 |
| rover.move() | Rex rolls forward. Energy: 80 | 80 |
| rover.move() | Rex rolls forward. Energy: 70 | 70 |
Trade off
Comparison matrix
From Press a button: rover.move(): every row here is a choice with a cost. Fill the prints column, then say which row you would actually pick and what you give up for it.
| call | prints | energy after |
|---|---|---|
| start | (nothing) | 100 |
| rover.move() | Rex rolls forward. Energy: 90 | 90 |
| rover.move() | Rex rolls forward. Energy: 80 | 80 |
| rover.move() | Rex rolls forward. Energy: 70 | 70 |
Ranking
Put in order
These are the steps of How to use any object, scrambled. Put them back in order before the next slide shows you.
thing.value.thing.action().thing.action(amount).Why: This is the order the recipe itself gives. Recalling the sequence without the slide in front of you is the difference between recognising the method and being able to run it — most of what goes wrong in practice is a step done out of turn.
Pattern
You'll repeat this for every object at camp - strings, lists, rovers, sensors:
thing.value.thing.action().thing.action(amount).Edge cases
Discussion prompt
How to use any object works on the cases you have just seen. Push it to the edge: what is the most degenerate input it still handles — empty, zero, one item, everything equal — and what is the first case where it stops being true? Name the case, not just "it breaks".
Hint: Try the smallest legal input, then the largest, then the one where two things collide. Methods are specified at their edges; the middle takes care of itself.
Answer:
You'll repeat this for every object at camp - strings, lists, rovers, sensors:
Section
Section 2
Intuition
A method name without () is just pointing at the button. Adding () is pressing it. Pointing does nothing; pressing makes it happen.
So rover.move is the button itself; rover.move() is the press that actually rolls the rover.
Analogy
Discussion prompt
Explain Parentheses mean "do it now" by analogy to something with no Python in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
A method name without () is just pointing at the button. Adding () is pressing it. Pointing does nothing; pressing makes it happen.
Anomaly
Predict first
A student writes this, and it looks reasonable:
You want Rex to move, but you leave off the ().
It is wrong. Say what breaks — and say it before you turn the page.
Correct: No parentheses - so you never press the button.
Add the () to actually call it.
Why: No parentheses - so you never press the button. Nothing rolls, energy doesn't change.
Trap
You want Rex to move, but you leave off the ().
Write rover.move
Why: No parentheses - so you never press the button. Nothing rolls, energy doesn't change.
Printing it shows <bound method Rover.move of ...>
Why: That's Python handing you the button itself, not running it. A super common silent bug: the line 'looks fine' but does nothing.
Add the () to actually call it.
Write rover.move()
Why: The parentheses press the button - the method runs.
Prints Rex rolls forward. Energy: 90
Why: Now the action happened and the energy attribute updated. Parentheses = do it now.
Elimination
Eliminate the wrong options
What does this do? rover = Rover("Rex") rover.move print(rover.energy)
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: rover.move with no parentheses does NOT call the method - it just refers to the button and throws it away. Energy is untouched, so print(rover.energy) shows 100.
Check
Rex starts at energy 100. Predict the result before tapping.
Check your understanding
What does this do?
rover = Rover("Rex")
rover.move
print(rover.energy)
Answer: A
Why: rover.move with no parentheses does NOT call the method - it just refers to the button and throws it away. Energy is untouched, so print(rover.energy) shows 100.
Section
Section 3
Worked example
Attributes are the object's stored values. Read them straight - no ().
rover = Rover("Rex")
print(rover.energy)
print(rover.facing)energy is a number, facing is a string. Both are just data sitting on the object.
| expression | kind | value |
|---|---|---|
| rover.energy | attribute (number) | 100 |
| rover.facing | attribute (string) | north |
Anomaly
Predict first
A student writes this, and it looks reasonable:
You add () to a piece of data, as if it were an action.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: energy is a number (100), not a function.
Read data with no parentheses.
Why: energy is a number (100), not a function. The parentheses tell Python to call 100 - which makes no sense.
Trap
You add () to a piece of data, as if it were an action.
Write rover.energy()
Why: energy is a number (100), not a function. The parentheses tell Python to call 100 - which makes no sense.
Crashes: TypeError: 'int' object is not callable
Why: Python is saying: you tried to call something that isn't callable. The number can't be 'run'.
Read data with no parentheses.
Write rover.energy
Why: Just the attribute name - Python hands back the value 100.
print(rover.energy) -> 100
Why: Data gets no (); actions get (). When you see 'object is not callable', you added () to data.
Break the constraint
Discussion prompt
The rule this trap just fixed:
Just the attribute name - Python hands back the value 100.
Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?
Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.
Answer:
energy is a number (100), not a function. The parentheses tell Python to call 100 - which makes no sense.
Prediction
Predict first
Which line crashes with TypeError: 'int' object is not callable?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: rover.energy()
Why: energy holds an int (100). Adding () tries to CALL that int, which Python refuses: 'int' object is not callable. Data is read with no parentheses.
Check
energy is a stored number; move is an action.
Check your understanding
Which line crashes with TypeError: 'int' object is not callable?
Answer: A
Why: energy holds an int (100). Adding () tries to CALL that int, which Python refuses: 'int' object is not callable. Data is read with no parentheses.
Section
Section 4
Concept
Calling a method can change the object's attributes. move() lowers energy; charge() raises it. The object keeps the new value - that stored state is the point of an object.
state — The current values of an object's attributes - what it remembers right now. Methods are how the state changes over time.
Matching
Match the pairs
Match each term to the definition this lesson gave it — not the one you would guess from the word.
Why: These are the working definitions of object, attribute, method, state as Objects, Part 1: What the Dot Means uses them. Pairing them correctly is the test of whether you could state each one with the slide switched off.
Worked example
Follow energy down and back up across a sequence of calls. The object carries the running value from one line to the next.
rover = Rover("Rex")
rover.move()
rover.move()
rover.charge(25)
print(rover.energy)charge(25) adds 25 to whatever energy is now - not to the starting 100.
| call | energy before | energy after |
|---|---|---|
| rover.move() | 100 | 90 |
| rover.move() | 90 | 80 |
| rover.charge(25) | 80 | 105 |
| print(rover.energy) | 105 | prints 105 |
Intuition
Each method call doesn't start fresh - it picks up the energy the last call left behind. The backpack keeps whatever you last put in it.
That memory is why a rover can run a long mission: every move() spends from the energy that's actually left.
Counterexample
Discussion prompt
Each method call doesn't start fresh - it picks up the energy the last call left behind. The backpack keeps whatever you last put in it.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Anomaly
Predict first
A student writes this, and it looks reasonable:
Thinking each move() starts from the original 100.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Assumes every call resets to 100 first, then subtracts 10.
Track the running value the object stores.
Why: Assumes every call resets to 100 first, then subtracts 10. But the object never resets on its own.
Trap
Thinking each move() starts from the original 100.
Predict energy = 90 after three moves
Why: Assumes every call resets to 100 first, then subtracts 10. But the object never resets on its own.
Reality: 100 -> 90 -> 80 -> 70
Why: Each call subtracts from the current state, not the starting value.
Track the running value the object stores.
Each move spends from what's left
Why: 90, then 80, then 70 - the state carries forward.
Energy resets only if YOU make a new rover
Why: Rover("Rex") again is a brand-new object back at 100; the old one keeps its 70.
Prediction
Predict first
rover = Rover("Rex") rover.move() rover.move() rover.charge(25) What is rover.energy now?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: 105
Why: 100 - 10 - 10 = 80 after the two moves, then + 25 = 105. charge adds to the current 80, not to the original 100.
Check
Rex starts at 100. move() spends 10; charge(n) adds n.
Check your understanding
rover = Rover("Rex")
rover.move()
rover.move()
rover.charge(25)
What is rover.energy now?
Answer: A
Why: 100 - 10 - 10 = 80 after the two moves, then + 25 = 105. charge adds to the current 80, not to the original 100.
Section
Section 5
Worked example
Some methods take an input. charge needs to know how much - that value goes inside the ().
rover = Rover("Rex")
rover.charge(25)
rover.charge(5)
print(rover.energy)charge(25) and charge(5) are the same action with different inputs.
| call | adds | energy after |
|---|---|---|
| start | - | 100 |
| rover.charge(25) | 25 | 125 |
| rover.charge(5) | 5 | 130 |
Concept
You can have two rovers at once. Each is a separate object with its own energy. Calling a method on one never touches the other.
This is how a camp team runs a whole fleet: one class, many independent rovers.
Intuition
Rex and Nova are like two students' backpacks. Taking something out of Rex's pack doesn't change what's in Nova's.
Figure (svg): Two separate backpacks side by side, Rex with energy 80 and Nova with energy 100, showing their data is independent.
Sorting
Sort into buckets
These are the pieces of Objects, Part 1: What the Dot Means, out of order. Put each one back under the part of the lesson it belongs to.
Worked example
Make two rovers. Move only Rex. Then read both energies.
rex = Rover("Rex")
nova = Rover("Nova")
rex.move()
rex.move()
print(rex.energy)
print(nova.energy)Only rex was moved, so only rex.energy changed.
| object | moves called | energy |
|---|---|---|
| rex | 2 | 80 |
| nova | 0 | 100 |
Comparison
Comparison matrix
From Rex moves; Nova doesn't care: refill the energy column from what you know. The rest of the table is as it appeared.
| object | moves called | energy |
|---|---|---|
| rex | 2 | 80 |
| nova | 0 | 100 |
Anomaly
Predict first
A student writes this, and it looks reasonable:
Treating energy like one global number for all rovers.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Assumes the rovers share a single energy value the way a global variable would.
Each object owns a separate copy of its attributes.
Why: Assumes the rovers share a single energy value the way a global variable would.
Trap
Treating energy like one global number for all rovers.
Move rex twice, expect nova at 80 too
Why: Assumes the rovers share a single energy value the way a global variable would.
Predict nova.energy = 80
Why: Wrong: nova was never moved, so it stays 100.
Each object owns a separate copy of its attributes.
rex.move() touches only rex
Why: energy lives inside each rover, not in one shared place.
rex.energy = 80, nova.energy = 100
Why: Independent objects, independent data. That's what 'its own data' means.
Two truths and a lie
Sort into buckets
Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.
().; You add () to a piece of data, as if it were an action.Elimination
Eliminate the wrong options
rex = Rover("Rex") nova = Rover("Nova") rex.move() What are rex.energy and nova.energy?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: Each rover has its own energy. rex.move() spends 10 from rex only (100 -> 90). nova was never moved, so it stays at its starting 100.
Check
Two rovers; only one is moved.
Check your understanding
rex = Rover("Rex")
nova = Rover("Nova")
rex.move()
What are rex.energy and nova.energy?
Answer: A
Why: Each rover has its own energy. rex.move() spends 10 from rex only (100 -> 90). nova was never moved, so it stays at its starting 100.
Section
Section 6 · build it yourself
Concept
The Rover class is already written and given to you. Your job is to pilot it: read its data and call its actions. Type every line yourself, run after each one, and read errors - don't erase them.
| # | do this | tool you'll use |
|---|---|---|
| 1 | make a rover and report its energy | Rover(name), .energy |
| 2 | drive it three times | .move() |
| 3 | recharge and give a final report | .charge(n), .energy |
Worked example
Your turn: make a rover named "Scout" and print its starting energy. Say out loud what number you expect before you run it.
Hint: Rover("Scout") builds it; read energy with no parentheses.
scout = Rover("Scout")
print(scout.name)
print(scout.energy)| line | prints |
|---|---|
| print(scout.name) | Scout |
| print(scout.energy) | 100 |
Worked example
Your turn: call move() three times, then print the energy. Predict the final number first.
Hint: each move() spends 10; the object remembers the running total.
scout.move()
scout.move()
scout.move()
print(scout.energy)| after | energy |
|---|---|
| move 1 | 90 |
| move 2 | 80 |
| move 3 | 70 |
Trade off
Comparison matrix
From Milestone 2 — drive it three times: every row here is a choice with a cost. Fill the energy column, then say which row you would actually pick and what you give up for it.
| after | energy |
|---|---|
| move 1 | 90 |
| move 2 | 80 |
| move 3 | 70 |
Worked example
Your turn: put it together - build, drive three times, recharge 25, and report. Predict the last line before running.
scout = Rover("Scout")
scout.move()
scout.move()
scout.move()
scout.charge(25)
print(scout.name, "has energy", scout.energy)| step | energy |
|---|---|
| start | 100 |
| three moves | 70 |
| charge(25) | 95 |
| final print | Scout has energy 95 |
If yours prints Scout has energy 95 - you just piloted an object with methods and attributes.
Comparison
Comparison matrix
From Milestone 3 — full program: refill the energy column from what you know. The rest of the table is as it appeared.
| step | energy |
|---|---|
| start | 100 |
| three moves | 70 |
| charge(25) | 95 |
| final print | Scout has energy 95 |
Worked example
Explain your program out loud, line by line: which lines read data (no parentheses) and which lines do an action (parentheses)?
Point to the one line where the object's state changed but nothing printed - that's a method quietly updating an attribute.
You can now beat all three of today's traps: missing (), calling data like energy(), and assuming two rovers share energy.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — The Dot & the Object · Methods — Actions You Call · Attributes — Data You Read · Methods Change the Data · Arguments & a Fleet · Your Turn: Drive the Rover. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
| you want to... | you write |
|---|---|
| read data | rover.energy (no parens) |
| do an action | rover.move() (parens) |
| pass an input | rover.charge(25) |
| make another object | nova = Rover("Nova") |
Next time (Lesson 2): you stop using someone else's Rover and write the class yourself - class, __init__, and self.
Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.