Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

argument
A value you put inside the parentheses when you call a function, which the function then receives.
block
A group of lines that belong together under one opening line, such as the body of an if or a loop.
branch
A path a program can take when a condition sends it one way or another.
call site
The place in the code where a function is called, as opposed to where it is defined.
class
A template that bundles data with the code that works on it; each copy has its own values.
dictionary
A collection of key and value pairs, where a key is used to look up its value.
exception
An error that stops the normal flow of a program unless some code catches it.
function
A named piece of code that does one job and can be called whenever you need it.
function object
A function treated as a value, so it can be stored in a variable, passed to another function, or returned.
indentation
The spaces at the start of a line that show which block it belongs to.
integer
A whole number with no decimal point, such as 3, 0 or -12.
list
An ordered collection of values that you can grow, shrink and reach into by position.
parameter
A name in a function definition that stands for the value the caller will supply.
return value
The result a function hands back to the code that called it.
scope
The part of a program where a name can be used; a name made inside a function is not visible outside it.
traceback
The report Python prints when a program fails, listing the calls that led to the error.
variable
A name that refers to a value, so you can use that value again later or change it.

Python from the ground up

Classes and objects

A blueprint and the things made from it: your own type with its own data, and the methods that work on it.

Part 9 of 15

Advanced16 min readBack to Courses

A blueprint and the things made from it

A class is a blueprint for a kind of thing. It says what every one of those things holds and what it can do. An object is one thing made from the blueprint — one recipe, one card, one account.

The data an object carries are its attributes, and the functions that work on it are its methods. A class is how a program stops passing the same few values around together and gives them a home.

One blueprint, two recipes

class Recipe:
    def __init__(self, name, minutes):
        self.name = name
        self.minutes = minutes

    def describe(self):
        return f"{self.name} takes {self.minutes} minutes."

flatbread = Recipe("Flatbread", 25)
soup = Recipe("Soup", 40)

print(flatbread.describe())
print(soup.describe())

__init__ sets the object up

__init__ runs the moment an object is made, and its job is to put the starting values in place. Recipe("Flatbread", 25) calls it with two arguments, and the new object leaves it holding a name and a number of minutes.

The underscores on both sides mark a name Python treats specially — it looks for this one at creation time. You rarely write any others, but every class that carries data has this one.

self is this object

Inside a method, self is the object the method was called on. self.name = name means "store this value on this object" — and because every object has its own, the flatbread’s 25 minutes and the soup’s 40 never mix.

That is also why the call looks lopsided: flatbread.describe() takes no arguments, though def describe(self) asks for one. The object before the dot fills self; you just do not have to say it twice.

From dictionary to class

Turn the two values into a small Recipe class: an __init__ that stores the name and the minutes, and a describe() method that returns the sentence. Then make two recipes and print what each one says.

Output
Click "Run" to execute your code

The dot looks the attribute up on the object

flatbread.describe() is two steps: find the attribute called describe on that object, then call it. The attribute comes from the class, because the object itself only stores data. That is why changing the class changes every object made from it, while changing one object’s minutes changes only that object.

A missing attribute raises AttributeError, and the message names the object’s type and the attribute it could not find. A typo in a method name and a method that was never defined look the same from the outside, so check the spelling before doubting the class.

Objects print in an unhelpful way by default

print(flatbread) shows something like <__main__.Recipe object at 0x...>, which says where the object lives and nothing about what it holds. That is not a bug; it is the default, and __str__ is the hook that replaces it. The address changes on every run, so it is useless for comparing two objects.

Until you write one, print the attributes you care about: print(flatbread.name, flatbread.minutes). The habit is useful anyway, because it forces you to decide which parts of an object are worth showing and which are internal. A describe method is often the better answer, and it can be reused by __str__ later.

If a few values always travel together, and the same functions always take all of them, they are asking to be a class.

Methods can change the object

A method is not limited to reading attributes. self.minutes += extra changes the object it was called on, and the new value is there for every later call. That is how an object keeps state across a program instead of being a bundle of values passed around.

Because each object has its own attributes, the change stays with that object. Two recipes made from the same class can hold different times, and extending one does not touch the other. The class describes the behaviour; each object carries its own copy of the data.

One method can call another

Inside one method, self can call another: self.summary() runs the other method on the same object. That is how a class builds a small vocabulary instead of repeating its own formatting in every method.

The double-underscore names such as __init__ are hooks Python looks for. __str__, for instance, decides what print(object) shows. You can ignore them until you need them; a single leading underscore is only a hint that a name is internal.

Three class mistakes: a method that forgets self in its parameter list cannot be called on an object; assigning name = name inside __init__ creates a local name and leaves the object empty; and a mutable value such as a list placed directly on the class is shared by every object made from it.

Try these next

  • Add an extend(extra) method that increases a recipe’s minutes, and call it on one of two recipes.
  • Print both objects after extending one, to prove the other is unchanged.
  • Remove self from a method’s parameter list and read the error before putting it back.

A timer you can extend

`__init__` and `describe` are ready. Add `extend(extra)` to increase the timer’s minutes, call it, and print the description again.

Output
Click "Run" to execute your code

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

When does __init__ run?