Classes

INPUT · Slides

The data and the work drift apart

01 / 07

Representing a member with a dictionary

When you met dictionaries in Chapter 2 you may have thought: if I want to represent a person or a shop, surely this is enough.

And for a while it is. The information for a single member goes into a dictionary like this.

member = {"name": "Aoi", "years": 3}print(member["name"])print(member["years"])

Result

Aoi
3

02 / 07

Writing the work that uses that data

Once the data exists, the work that uses it comes next. Start with tidying the name for display, gathered into a function the way Chapter 3 showed.

It takes the whole dictionary and pulls out what it needs from inside.

def label(member):    name = member["name"]    return f"{name} (member)"member = {"name": "Aoi", "years": 3}print(label(member))

Result

Aoi (member)

03 / 07

The work keeps piling up

Display is not the only thing you want from a member. You want the yearly fee worked out. You want to decide whether they can leave.

Each time, one more function that takes the dictionary gets added.

def yearly_fee(member):    if member["years"] >= 3:        return 4000    return 5000member = {"name": "Aoi", "years": 3}print(yearly_fee(member))

Result

4000

04 / 07

The data and the work sit in different places

That makes three functions. Every one of them has to know that a member dictionary holds name and years.

But the dictionary itself is kept somewhere else entirely. What a member is has been scattered all over the file.

def label(member):    name = member["name"]    years = member["years"]    return f"{name} (member, year {years})"def yearly_fee(member):    if member["years"] >= 3:        return 4000    return 5000def can_leave(member):    return member["years"] >= 1member = {"name": "Aoi", "years": 3}print(label(member))print(yearly_fee(member))print(can_leave(member))

Result

Aoi (member, year 3)
4000
True

05 / 07

Rename one key and

Suppose you want "years" to be called "yrs" instead. There is one place in the dictionary to fix, and that is not the end of it.

You end up hunting down every function that says member["years"]. Miss one and that one line falls over with a KeyError.

member = {"name": "Aoi", "yrs": 3}print(member["years"])

Result

KeyError: 'years'

06 / 07

More members does not fix the scattering

Put plenty of members in a list and you can work through them together. That much is fine.

But there is still nowhere that says what a member is. The shape of the dictionary lives only in the memory of whoever wrote it, so a dictionary with an item missing gets made without a murmur.

def label(member):    name = member["name"]    years = member["years"]    return f"{name} (member, year {years})"members = [    {"name": "Aoi", "years": 3},    {"name": "Hinata", "years": 1},]for member in members:    print(label(member))

Result

Aoi (member, year 3)
Hinata (member, year 1)

07 / 07

Next, all of this goes into one box

The machinery for gathering up what has scattered is the class, and it is what this chapter is about.

You write in one place what data a member holds and what a member can do. Then, when you want to change the shape, there is one place to look.

This lesson still does not write a class. The point is to feel the awkwardness by hand first. From the next lesson we start putting it right.