Objects, Part 2: Write Your Own Class

Lesson 2 of 8 in the Pre-COSMOS series, 41 slides, and the leap from USING a provided Rover to WRITING the class yourself - the heaviest new lift of the eight lessons. It is built concrete and tiny across five ideas. First, class Rover defines a new TYPE, a blueprint, while an instance is one rover built from it. Second, __init__(self, name) is the setup method that runs automatically when you make one, storing the starting attributes with self.name = ... and self.energy = 100. Third, self means this particular object. Fourth, methods are written as def move(self): and def charge(self, amount):, and they change self.energy. Fifth, rex = Rover("Rex") and nova = Rover("Nova") each build fresh, independent state. The three traps are the classic class-writing errors: forgetting self in a method header, which gives TypeError: takes 0 positional arguments but 1 was given; dropping the self. prefix in __init__, which surfaces later as AttributeError: object has no attribute 'energy'; and forgetting the argument, which gives TypeError: __init__() missing 1 required positional argument: 'name'. There are five checks and a scaffolded your-turn build in which students write the Rover class from scratch to reproduce an energy of 70 and then 95. Every snippet was run on CPython 3.12, with the outputs and error text copied verbatim.

Subject: Python · 67 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. Objects, Part 2: Write Your Own Class

Title

Pre-COSMOS · Lesson 2 of 8

Last time you drove a Rover someone else built. Today you build the Rover itself - class, __init__, and self.

2. What you will be able to do

Objectives

This is the biggest new step of the whole camp - and it will feel strange at first. That's normal. We go slow and tiny. By the end you can:

3. What survived from Objects, Part 1: What the Dot Means?

Warm-up

Discussion prompt

Before we open Objects, Part 2: Write Your Own Class: without looking back, what was the main idea of Objects, Part 1: What the Dot Means, 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 1 of 8 (41 slides): objects through USE, not class-writing. The dot you've typed all along (robot.look(), "hi".upper(), nums.append()) reaches inside an object; an object bundles data (attributes, read with no parens) with actions (methods, called with parens).

4. Yesterday vs today

Concept

Figure (svg): A cookie-cutter labeled 'class Rover' stamping out two separate cookies labeled Rex and Nova, showing that the class is the shape and the instances are the things made from it.

One blueprint stamps out many rovers.

Lesson 1: you were handed a rover and pressed its buttons. Today: you write the blueprint those rovers are stamped from.

Same Rover, same .move(), same .energy - but now you decide what's inside.

5. Break it if you can: Yesterday vs today

Counterexample

Discussion prompt

Same Rover, same .move(), same .energy - but now you decide what's inside.

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.

6. Today's roadmap

Concept

Five tiny pieces. Put together, they are one whole Rover class:

class
Define a new type.
__init__
Setup that runs on build.
self
This object.
methods
Actions that change state.

7. By analogy: Today's roadmap

Analogy

Discussion prompt

Explain Today's roadmap 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:

Five tiny pieces. Put together, they are one whole Rover class:

8. class — a Blueprint

Section

Section 1

9. A class defines a TYPE

Concept

class Rover: does not make a rover. It defines a new type - a blueprint that says what every rover will have and will do.

From one blueprint you can build as many rovers as you want. The blueprint is the plan; a rover is a real thing made from the plan.

10. Teach it back: A class defines a TYPE

Explain it

Discussion prompt

Explain A class defines a TYPE 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:

class Rover: does not make a rover. It defines a new type - a blueprint that says what every rover will have and will do.

11. Two words for today

Concept

class — A blueprint that defines a new type of object - what data it holds and what actions it can do. Written: class Rover:

instance — One actual object built from a class. rex = Rover("Rex") makes an instance. Many instances can come from one class.

12. Blueprint vs building

Intuition

Figure (svg): A flat blueprint sheet on the left and a built 3D house on the right, joined by an arrow, showing the class is the plan and the instance is the real thing.

You can draw the plan once and build many houses.

A blueprint for a house isn't a house - you can't live in a drawing. But from one blueprint a crew can build a whole street of houses.

class Rover: is the drawing. Rover("Rex") is the crew building one real rover from it.

13. The smallest possible class

Worked example

Here is a Rover blueprint with nothing in it yet, and one instance built from it. pass just means 'empty body for now'.

class Rover:
    pass

rex = Rover()
print(type(rex))

Rover() builds an instance; type(rex) shows it really is a Rover.

linewhat happensprints
class Rover:defines the type(nothing)
rex = Rover()builds one instance(nothing)
print(type(rex))shows the type<class '__main__.Rover'>

14. Fill in: what happens for The smallest possible class

Comparison

Comparison matrix

From The smallest possible class: refill the what happens column from what you know. The rest of the table is as it appeared.

linewhat happensprints
class Rover:defines the type(nothing)
rex = Rover()builds one instance(nothing)
print(type(rex))shows the type<class '__main__.Rover'>

15. Rebuild the recipe: How to write any class

Ranking

Put in order

These are the steps of How to write any class, scrambled. Put them back in order before the next slide shows you.

  1. Name the type: class Rover:
  2. Write __init__(self, ...) and store each starting value with self.x = ...
  3. Add methods as def action(self, ...):, always self first.
  4. Change state inside with self.attribute = ...
  5. Build instances with name = Rover("...") - each runs __init__ fresh.

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.

16. How to write any class

Pattern

Here is the whole recipe for today, start to finish. Every piece gets its own section below - this is the map:

  1. Name the type: class Rover:
  2. Write __init__(self, ...) and store each starting value with self.x = ...
  3. Add methods as def action(self, ...):, always self first.
  4. Change state inside with self.attribute = ...
  5. Build instances with name = Rover("...") - each runs __init__ fresh.

17. Where does it stop working: How to write any class

Edge cases

Discussion prompt

How to write any class 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:

Here is the whole recipe for today, start to finish. Every piece gets its own section below - this is the map:

18. Rule out three: Check: blueprint or thing?

Elimination

Eliminate the wrong options

In rex = Rover("Rex"), which part is the class (blueprint) and which is the instance (the built object)?

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.

  • A. Rover is the class; rex is the instance
  • B. rex is the class; Rover is the instance
  • C. Both Rover and rex are classes
  • D. "Rex" is the class; rex is the instance

Survives elimination: A

Why: Rover is the blueprint (the type). Calling Rover("Rex") builds one object from that blueprint, and rex is the name for that built instance.

19. Check: blueprint or thing?

Check

Keep the two words straight before we add anything.

Check your understanding

In rex = Rover("Rex"), which part is the class (blueprint) and which is the instance (the built object)?

  • A. Rover is the class; rex is the instance (correct)
  • B. rex is the class; Rover is the instance
  • C. Both Rover and rex are classes
  • D. "Rex" is the class; rex is the instance

Answer: A

Why: Rover is the blueprint (the type). Calling Rover("Rex") builds one object from that blueprint, and rex is the name for that built instance.

Why B tempts people
Backwards. Rover is the shared blueprint you defined with class; rex is the one object stamped out of it.
Why C tempts people
Only Rover is a class. rex is a single instance - one concrete rover, not a blueprint.
Why D tempts people
"Rex" is just the name string passed in as data; the class is Rover, the blueprint being built from.

20. __init__ — the Setup Method

Section

Section 2

21. __init__ runs automatically

Concept

An empty rover is useless. We need every new rover to start with a name and energy. That's the job of __init__ - the setup method.

You never call __init__ yourself. Python runs it automatically the moment you write Rover("Rex"). Those double underscores are part of the name.

22. The setup that runs on power-up

Intuition

Think of __init__ as the boot sequence of a robot. The instant it's switched on, it sets its name tag and fills its battery to 100 - before you ask it to do anything.

You don't press a 'boot' button; flipping the power on (Rover("Rex")) runs the boot sequence for you.

23. Write __init__ to set the start state

Worked example

Inside __init__, store the starting values onto the object with self.. The name comes in as an argument; energy and facing are fixed.

class Rover:
    def __init__(self, name):
        self.name = name
        self.energy = 100
        self.facing = "north"

rex = Rover("Rex")
print(rex.name, rex.energy, rex.facing)

Rover("Rex") runs __init__ with name = "Rex", storing three attributes.

line in __init__storesvalue
self.name = namename attributeRex
self.energy = 100energy attribute100
self.facing = "north"facing attributenorth

24. What each one costs: Write __init__ to set the start state

Trade off

Comparison matrix

From Write __init__ to set the start state: every row here is a choice with a cost. Fill the stores column, then say which row you would actually pick and what you give up for it.

line in __init__storesvalue
self.name = namename attributeRex
self.energy = 100energy attribute100
self.facing = "north"facing attributenorth

25. Something is wrong here: forgetting the self. prefix

Anomaly

Predict first

A student writes this, and it looks reasonable:

Inside __init__ you write energy = 100 - a plain variable, no self.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Without self., energy is just a local variable that vanishes the second __init__ ends.

Use self.energy = 100 to attach it to the object.

Why: Without self., energy is just a local variable that vanishes the second __init__ ends. It is never stored on the rover.

26. Trap: forgetting the self. prefix

Trap

The trap

Inside __init__ you write energy = 100 - a plain variable, no self.

Write energy = 100 instead of self.energy = 100

Why: Without self., energy is just a local variable that vanishes the second __init__ ends. It is never stored on the rover.

Later rex.energy crashes: AttributeError: 'Rover' object has no attribute 'energy'

Why: The attribute was never saved onto the object, so there is nothing to read back.

The fix

Use self.energy = 100 to attach it to the object.

Write self.energy = 100

Why: self. stores the value on this rover, so it survives after __init__ finishes.

Now rex.energy -> 100

Why: The attribute lives on the object. Rule: in __init__, anything you want to keep needs self. in front.

27. Check: when does __init__ run?

Check

Think about the exact moment the setup happens.

Check your understanding

When does __init__ run, and what is its job?

  • A. Automatically when you build an instance, e.g. Rover("Rex"); it sets the starting attributes (correct)
  • B. Only when you call rex.__init__() by hand, after building
  • C. Once, when Python first reads the class Rover: line
  • D. Every time you call rex.move(), to reset the rover

Answer: A

Why: Writing Rover("Rex") builds a new instance and Python automatically runs __init__ with that name, storing self.name, self.energy, and self.facing as the starting state.

Why B tempts people
You never call __init__ by hand. Python runs it for you the moment you build an instance with Rover(...).
Why C tempts people
The class Rover: line only defines the blueprint; no rover exists yet, so __init__ has not run. It runs when you build one.
Why D tempts people
move() is a separate method. __init__ runs once at build time, not on every action, and it does not reset an existing rover.

28. self — This Object

Section

Section 3

29. self is the rover speaking

Concept

Every method's first parameter is self. It stands for the particular object the method was called on. self.energy means this rover's energy.

self — The first parameter of every method - it refers to the specific object you called the method on. self.energy is THIS object's energy, not anyone else's.

30. Term to definition: Objects, Part 2: Write Your Own Class

Matching

Match the pairs

Match each term to the definition this lesson gave it — not the one you would guess from the word.

  • t1. class
  • t2. instance
  • t3. self
  • d1. A blueprint that defines a new type of object - what data it holds and what actions it can do. Written: class Rover:
  • d2. One actual object built from a class. rex = Rover("Rex") makes an instance. Many instances can come from one class.
  • d3. The first parameter of every method - it refers to the specific object you called the method on. self.energy is THIS object's energy, not anyone else's.

Why: These are the working definitions of class, instance, self as Objects, Part 2: Write Your Own Class uses them. Pairing them correctly is the test of whether you could state each one with the slide switched off.

31. self is the word "my"

Intuition

Figure (svg): Two rovers Rex and Nova; an arrow from the word self points to whichever rover is currently speaking, here Rex.

When Rex runs move(), self IS Rex.

When you write rex.move(), Python quietly passes rex in as self. So inside move, self is Rex - self.energy is Rex's energy.

Call nova.move() instead and self becomes Nova. self is just the word 'my' for whichever rover is currently doing the action.

32. self points at the right rover

Worked example

Two rovers, one method. Watch self switch depending on who you call it on.

rex = Rover("Rex")
nova = Rover("Nova")
rex.move()
print(rex.energy)
print(nova.energy)

rex.move() makes self be rex, so only rex.energy changes.

callself isenergy after
rex.move()rexrex 90
(nova untouched)-nova 100

33. Where does each piece belong: Objects, Part 2: Write Your Own Class

Sorting

Sort into buckets

These are the pieces of Objects, Part 2: Write Your Own Class, out of order. Put each one back under the part of the lesson it belongs to.

class — a Blueprint
A class defines a TYPE; Two words for today; Blueprint vs building
__init__ — the Setup Method
__init__ runs automatically; The setup that runs on power-up; Write __init__ to set the start state
self — This Object
self is the rover speaking; self is the word "my"; self points at the right rover
s1
class — a Blueprint is where Objects, Part 2: Write Your Own Class puts A class defines a TYPE, Two words for today, Blueprint vs building. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s2
__init__ — the Setup Method is where Objects, Part 2: Write Your Own Class puts __init__ runs automatically, The setup that runs on power-up, Write __init__ to set the start state. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s3
self — This Object is where Objects, Part 2: Write Your Own Class puts self is the rover speaking, self is the word "my", self points at the right rover. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.

34. Something is wrong here: forgetting self in a method header

Anomaly

Predict first

A student writes this, and it looks reasonable:

You define the method as def move(): - no self in the header.

It is wrong. Say what breaks — and say it before you turn the page.

Correct: Python still passes the rover in automatically when you call rex.move(), so the method receives 1 argument it has no slot for.

Put self first in every method header.

Why: Python still passes the rover in automatically when you call rex.move(), so the method receives 1 argument it has no slot for.

35. Trap: forgetting self in a method header

Trap

The trap

You define the method as def move(): - no self in the header.

Write def move(): (no parameter)

Why: Python still passes the rover in automatically when you call rex.move(), so the method receives 1 argument it has no slot for.

rex.move() crashes: TypeError: Rover.move() takes 0 positional arguments but 1 was given

Why: The '1' that was given is the rover itself. With no self slot to catch it, Python errors out.

The fix

Put self first in every method header.

Write def move(self):

Why: Now there's a slot for the rover Python passes in. Inside, self.energy is that rover's energy.

rex.move() runs and prints Rex rolls forward. Energy: 90

Why: Rule: every method's first parameter is self, even if you never typed it at the call site.

36. Break it on purpose: forgetting self in a method header

Break the constraint

Discussion prompt

The rule this trap just fixed:

Rule: every method's first parameter is self, even if you never typed it at the call site.

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:

Python still passes the rover in automatically when you call rex.move(), so the method receives 1 argument it has no slot for.

37. Answer it before you see the options: Check: what is self?

Prediction

Predict first

Inside def move(self):, what does self refer to when you call nova.move()?

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: The particular object move was called on - here, nova

Why: self is the first parameter of a method and stands for the specific instance you called it on. nova.move() passes nova in as self, so self.energy is nova's energy.

38. Check: what is self?

Check

One sentence answer - what does self refer to?

Check your understanding

Inside def move(self):, what does self refer to when you call nova.move()?

  • A. The particular object move was called on - here, nova (correct)
  • B. The Rover class itself (the blueprint)
  • C. Always the first rover ever created
  • D. A keyword you must spell exactly 'self' or Python errors

Answer: A

Why: self is the first parameter of a method and stands for the specific instance you called it on. nova.move() passes nova in as self, so self.energy is nova's energy.

Why B tempts people
self is an instance, not the class. nova.move() makes self be nova - one built object, not the Rover blueprint.
Why C tempts people
self is whatever object you called the method on this time. nova.move() makes self be nova, regardless of creation order.
Why D tempts people
self is a convention, not a keyword - any name would work - but it must be the first parameter; the error in this lesson is from omitting it, not misspelling it.

39. Methods That Change State

Section

Section 4

40. Methods live inside the class

Concept

A method is just a def written inside the class, with self as its first parameter. It can read and change the object's attributes through self.

move(self) lowers self.energy; charge(self, amount) raises it by amount. The change sticks because it's stored on the object.

41. Teach it back: Methods live inside the class

Explain it

Discussion prompt

Explain Methods live inside the class 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:

A method is just a def written inside the class, with self as its first parameter. It can read and change the object's attributes through self.

42. Write move and charge

Worked example

Both methods change self.energy and then print. charge takes an extra input, amount, after self.

class Rover:
    def __init__(self, name):
        self.name = name
        self.energy = 100
    def move(self):
        self.energy -= 10
        print(f"{self.name} rolls forward. Energy: {self.energy}")
    def charge(self, amount):
        self.energy += amount
        print(f"{self.name} charges. Energy: {self.energy}")

rex = Rover("Rex")
rex.move()
rex.charge(5)

move subtracts 10; charge(5) adds 5 to whatever energy is now.

callenergy beforeenergy afterprints
rex = Rover("Rex")-100(nothing)
rex.move()10090Rex rolls forward. Energy: 90
rex.charge(5)9095Rex charges. Energy: 95

43. Full trace: build, move twice, charge

Worked example

Walk every line. The object carries energy from one line to the next - this is the whole point of writing the class.

rex = Rover("Rex")
rex.move()
rex.move()
rex.charge(25)
print(rex.energy)

charge(25) adds to the current 80, not the starting 100.

lineself.energy beforeself.energy afterprints
rex = Rover("Rex")-100(nothing)
rex.move()10090Rex rolls forward. Energy: 90
rex.move()9080Rex rolls forward. Energy: 80
rex.charge(25)80105Rex charges. Energy: 105
print(rex.energy)105105105

44. Answer it before you see the options: Check: predict the output

Prediction

Predict first

rex = Rover("Rex") rex.move() rex.charge(25) print(rex.energy) What prints on the last line?

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: 115

Why: Start at 100. move() subtracts 10 -> 90. charge(25) adds 25 to the current 90 -> 115. So rex.energy is 115.

45. Check: predict the output

Check

Use the Rover class with move() and charge(amount). Trace it on paper first.

Check your understanding

rex = Rover("Rex")
rex.move()
rex.charge(25)
print(rex.energy)

What prints on the last line?

  • A. 115 (correct)
  • B. 125
  • C. 75
  • D. 90

Answer: A

Why: Start at 100. move() subtracts 10 -> 90. charge(25) adds 25 to the current 90 -> 115. So rex.energy is 115.

Why B tempts people
Adds 25 to the original 100, ignoring the move(). charge works on the current energy (90 after the move), giving 115.
Why C tempts people
Subtracts 25 instead of adding it. charge raises energy by amount, so 90 + 25 = 115, not 90 - 25.
Why D tempts people
That's the energy right after move() but before charge(25). The charge then adds 25 to reach 115.

46. Making Instances

Section

Section 5

47. Each instance is independent

Concept

Rover("Rex") and Rover("Nova") each run __init__ separately, building fresh state. Two rovers, two separate sets of attributes.

Changing rex.energy never touches nova.energy. One class, many independent objects - that's how a whole fleet runs from one blueprint.

48. By analogy: Each instance is independent

Analogy

Discussion prompt

Explain Each instance is independent 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:

Rover("Rex") and Rover("Nova") each run __init__ separately, building fresh state. Two rovers, two separate sets of attributes.

49. Two rovers, fresh state each

Worked example

Build two. __init__ runs once per rover, so each starts at 100. Move only Rex.

rex = Rover("Rex")
nova = Rover("Nova")
rex.move()
print(rex.name, rex.energy)
print(nova.name, nova.energy)

Only rex.move() ran, so only rex.energy dropped. Nova stays fresh.

instance__init__ ranmovesenergy
rexyes (name=Rex)190
novayes (name=Nova)0100

50. Fill in: energy for Two rovers, fresh state each

Comparison

Comparison matrix

From Two rovers, fresh state each: refill the energy column from what you know. The rest of the table is as it appeared.

instance__init__ ranmovesenergy
rexyes (name=Rex)190
novayes (name=Nova)0100

51. Something is wrong here: forgetting to pass the argument

Anomaly

Predict first

A student writes this, and it looks reasonable:

__init__(self, name) needs a name, but you build with empty ().

It is wrong. Say what breaks — and say it before you turn the page.

Correct: __init__ expects a name argument (after self), but you passed nothing for it.

Pass the name inside the parentheses.

Why: __init__ expects a name argument (after self), but you passed nothing for it.

52. Trap: forgetting to pass the argument

Trap

The trap

__init__(self, name) needs a name, but you build with empty ().

Write rex = Rover()

Why: __init__ expects a name argument (after self), but you passed nothing for it.

Crashes: TypeError: Rover.__init__() missing 1 required positional argument: 'name'

Why: Python is telling you exactly which parameter had no value: name.

The fix

Pass the name inside the parentheses.

Write rex = Rover("Rex")

Why: "Rex" fills the name parameter, so __init__ can run and set self.name.

Builds the rover; rex.name -> Rex

Why: Rule: whatever __init__ lists after self, you must supply when you build the instance.

53. Which of these survive contact with Objects, Part 2: Write Your Own Class?

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.

Holds up
Same Rover, same .move(), same .energy - but now you decide what's inside.; Five tiny pieces. Put together, they are one whole Rover class:; class Rover: does not make a rover. It defines a new type - a blueprint that says what every rover will have and will do.
Breaks
Inside __init__ you write energy = 100 - a plain variable, no self.; You define the method as def move(): - no self in the header.
sound
These are stated as this lesson states them — each one survives the edge cases Objects, Part 2: Write Your Own Class puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

54. Rule out three: Check: the missing-self error

Elimination

Eliminate the wrong options

class Rover: def __init__(self, name): self.name = name self.energy = 100 def move(): self.energy -= 10 rex = Rover("Rex") rex.move() What happens on rex.move()?

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.

  • A. TypeError: Rover.move() takes 0 positional arguments but 1 was given
  • B. It runs fine and energy becomes 90
  • C. AttributeError: 'Rover' object has no attribute 'energy'
  • D. TypeError: __init__() missing 1 required positional argument: 'name'

Survives elimination: A

Why: rex.move() automatically passes rex as the first argument, but def move(): has no parameter to receive it. Python reports it took 0 positional arguments but 1 was given.

55. Check: the missing-self error

Check

A camper defines move without self. Predict what happens.

Check your understanding

class Rover:
def __init__(self, name):
self.name = name
self.energy = 100
def move():
self.energy -= 10

rex = Rover("Rex")
rex.move()

What happens on rex.move()?

  • A. TypeError: Rover.move() takes 0 positional arguments but 1 was given (correct)
  • B. It runs fine and energy becomes 90
  • C. AttributeError: 'Rover' object has no attribute 'energy'
  • D. TypeError: __init__() missing 1 required positional argument: 'name'

Answer: A

Why: rex.move() automatically passes rex as the first argument, but def move(): has no parameter to receive it. Python reports it took 0 positional arguments but 1 was given.

Why B tempts people
It cannot run: with no self parameter, the rover Python passes in has nowhere to go, so the call errors before the body executes.
Why C tempts people
That's the different trap - dropping self. inside __init__. Here __init__ is correct; the bug is the missing self in the move header.
Why D tempts people
That error comes from building with Rover() and no name. Here Rover("Rex") is fine; the failure is at the rex.move() call.

56. Your Turn: Build the Rover

Section

Section 6 · build it yourself

57. The build: write the Rover class from scratch

Concept

No more provided class - you write all of it. Build it one piece at a time. Type every line yourself, run after each addition, and read errors - they tell you exactly what's missing.

#build thistool you'll use
1class + __init__ with name and energyclass, def __init__(self, name), self.x = ...
2a move methoddef move(self):, self.energy -= 10
3a charge method with an inputdef charge(self, amount):, self.energy += amount
4a full program: build, move 3x, charge 25Rover("..."), .move(), .charge(25)

58. Break it if you can: The build: write the Rover class from scratch

Counterexample

Discussion prompt

No more provided class - you write all of it. Build it one piece at a time. Type every line yourself, run after each addition, and read errors - they tell you exactly what's missing.

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.

59. Milestone 1 — class + __init__

Worked example

Your turn: write class Rover: with an __init__ that stores name and sets energy to 100. Build one named "Scout" and print both. Predict what prints first.

Hint: the header is def __init__(self, name):. Store with self.name = name and self.energy = 100 - don't forget the self.

class Rover:
    def __init__(self, name):
        self.name = name
        self.energy = 100

scout = Rover("Scout")
print(scout.name)
print(scout.energy)
lineprints
print(scout.name)Scout
print(scout.energy)100

60. Milestone 2 — add move()

Worked example

Your turn: add a move method that spends 10 energy and prints. Then move Scout once. Predict the energy it prints.

Hint: the header must start with self - def move(self):. Change state with self.energy -= 10.

class Rover:
    def __init__(self, name):
        self.name = name
        self.energy = 100
    def move(self):
        self.energy -= 10
        print(f"{self.name} rolls forward. Energy: {self.energy}")

scout = Rover("Scout")
scout.move()
callenergy afterprints
scout.move()90Scout rolls forward. Energy: 90

61. Milestone 3 — add charge(amount)

Worked example

Your turn: add a charge method that takes an amount and adds it to energy. Move once, then charge 25. Predict the final energy.

Hint: the header takes an extra input after self - def charge(self, amount):. Add it with self.energy += amount.

    def charge(self, amount):
        self.energy += amount
        print(f"{self.name} charges. Energy: {self.energy}")

scout = Rover("Scout")
scout.move()
scout.charge(25)
callenergy afterprints
scout.move()90Scout rolls forward. Energy: 90
scout.charge(25)115Scout charges. Energy: 115

62. What each one costs: Milestone 3 — add charge(amount)

Trade off

Comparison matrix

From Milestone 3 — add charge(amount): every row here is a choice with a cost. Fill the energy after column, then say which row you would actually pick and what you give up for it.

callenergy afterprints
scout.move()90Scout rolls forward. Energy: 90
scout.charge(25)115Scout charges. Energy: 115

63. Milestone 4 — full program

Worked example

Your turn: put the whole class together, then build a rover, move 3 times, charge 25, and report. Predict the two key numbers: energy after the moves, and at the end.

class Rover:
    def __init__(self, name):
        self.name = name
        self.energy = 100
    def move(self):
        self.energy -= 10
        print(f"{self.name} rolls forward. Energy: {self.energy}")
    def charge(self, amount):
        self.energy += amount
        print(f"{self.name} charges. Energy: {self.energy}")

scout = Rover("Scout")
scout.move()
scout.move()
scout.move()
scout.charge(25)
stepenergy afterprints
start100(nothing)
move 190Scout rolls forward. Energy: 90
move 280Scout rolls forward. Energy: 80
move 370Scout rolls forward. Energy: 70
charge(25)95Scout charges. Energy: 95

If your run hits 70 after the moves and 95 after the charge - you wrote a working class from scratch.

64. Fill in: energy after for Milestone 4 — full program

Comparison

Comparison matrix

From Milestone 4 — full program: refill the energy after column from what you know. The rest of the table is as it appeared.

stepenergy afterprints
start100(nothing)
move 190Scout rolls forward. Energy: 90
move 280Scout rolls forward. Energy: 80
move 370Scout rolls forward. Energy: 70
charge(25)95Scout charges. Energy: 95

65. Show it off

Worked example

Explain your class out loud: point to the class line (the blueprint), the __init__ (the setup that ran when you built Scout), and one self. (the rover storing its own data).

Stress-test it: temporarily delete the self from def move(self): and run - watch the exact TypeError appear, then put it back. You just met the trap on purpose and beat it.

You can now beat all three of today's traps: missing self in a header, missing self. in __init__, and a missing argument in Rover().

66. Connect it up: Objects, Part 2: Write Your Own Class

Connect it up

Draw it

One page, no notation unless you need it: draw how these connect — class — a Blueprint · __init__ — the Setup Method · self — This Object · Methods That Change State · Making Instances · Your Turn: Build the Rover. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.

67. What you can do now

Recap

you want to...you write
define the typeclass Rover:
set start statedef __init__(self, name): self.energy = 100
add an actiondef move(self): self.energy -= 10
build an instancerex = Rover("Rex")

Next time (Lesson 3): now that you can write a class, we give rovers more than one job - several methods and attributes working together.

Sources

  1. Python 3 Tutorial - Classes (class definitions, __init__, instance objects, self)
  2. Python 3 - Standard data model: __init__ and instance creation
  3. All snippets executed on CPython 3.12; output copied verbatim. Author verification run, 2026-06-24 (Pre-COSMOS Lesson 2 of 8). — Author verification run, 2026-06-24 (Pre-COSMOS Lesson 2 of 8).

Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108