Define a class and create objects
A dictionary can hold a customer, but nothing says which keys a customer must have. A class describes a kind of object once; every object made from it gets the same attributes, filled in by __init__.
- Write a class with an
__init__that stores each argument as an attribute onself - Create several objects from one class and read their attributes with a dot
- Build a list of objects from rows of data and work with it like any other list
So far a customer has been a dictionary: {"customer_id": "C00077", "name": "Jamal Walker", "city": "Houston"}. Nothing in the program says which keys a customer must have; a typo like "citty" is only discovered when something reads it.
A class describes a kind of object once. class Customer: starts the description. Inside it, the special function __init__ (two underscores each side) runs every time a new customer is created. Its first parameter, by convention called self, is the new object itself; the others are the values you pass in. self.city = city stores a value as an attribute of that object.
Calling the class, Customer("C00077", "Jamal Walker", "Houston"), creates a new object, runs __init__ on it with those three values, and gives you the object. jamal.city reads one attribute back.
Run each example to see what it prints. Running examples doesn't count toward progress.
class Customer: def __init__(self, customer_id, name, city): self.customer_id = customer_id self.name = name self.city = city jamal = Customer("C00077", "Jamal Walker", "Houston") grace = Customer("C01338", "Grace Walker", "New York") print(jamal.name, "lives in", jamal.city) print(grace.customer_id, grace.city) print(type(jamal).__name__, jamal is grace)
class Customer: def __init__(self, customer_id, name, city): self.customer_id = customer_id self.name = name city = city jamal = Customer("C00077", "Jamal Walker", "Houston") print(jamal.name) print(jamal.city)
Objects are values like any other: they go into lists, are passed to functions and returned from them. A common first job is turning rows of data (from a CSV file, say) into objects, after which the rest of the program reads customer.city instead of row["city"].
class Customer: def __init__(self, customer_id, name, city): self.customer_id = customer_id self.name = name self.city = city rows = [ {"customer_id": "C00038", "first_name": "Nora", "last_name": "Garcia", "city": "New York"}, {"customer_id": "C00077", "first_name": "Jamal", "last_name": "Walker", "city": "Houston"}, {"customer_id": "C01338", "first_name": "Grace", "last_name": "Walker", "city": "New York"}, ] customers = [] for row in rows: full_name = row["first_name"] + " " + row["last_name"] customers.append(Customer(row["customer_id"], full_name, row["city"])) for customer in customers: if customer.city == "New York": print(customer.customer_id, customer.name) print(len(customers), "customers loaded")
When to use it: when a kind of record has a fixed set of fields and is passed around a program: customers, orders, products. (Later lessons add the functions that belong to it.)
Mistakes to avoid:
- Forgetting
self.when storing, so the value is lost (above). - Leaving
selfout ofdef __init__(...): the call then has one argument too many and fails with TypeError. - Passing
selfyourself:Customer(jamal, "C00077", ...)is one argument too many. - Class names in
lower_case: the convention isCapitalisedWords, soCustomerreads as a class andcustomeras one object.
class Name:describes a kind of object; callingName(...)creates one and runs__init__.selfis the object being created;self.attr = valuestores an attribute on it.- Each object has its own attributes; read them with a dot.
- Next: what happens when two names refer to the same object.