Classes & objects
Define classes, __init__ and self, instance vs class attributes, __repr__/__str__ and encapsulation.
So far you've stored data in variables, lists and dicts, and logic in functions. Object-oriented programming (OOP) bundles the two: a class defines a new type with its own data (attributes) and behaviour (methods). You've been using objects all along — every string, list and file is one. Now you'll create your own.
Your first class#
The vocabulary:
- A class (
Dog) is a blueprint. By convention its name is inPascalCase. - An instance or object (
rex,luna) is a concrete thing built from the blueprint. Each has its own attribute values. __init__is the initialiser. CallingDog("Rex", 3)creates a new object and then runs__init__on it with those arguments.- A method is a function defined inside a class. Calling
rex.bark()automatically passesrexas the first argument, conventionally namedself.
rex.bark() is just a convenient spelling of Dog.bark(rex). That's all self is — the object the method was called on.
Why bother with classes?#
Compare a dict-based bank account:
Any code can change the data in any way, and the rules ("balance can't go negative") live nowhere in particular. A class keeps data and the rules that protect it together:
This is encapsulation: the object owns its state, and the methods are the sanctioned way to change it.
Instance attributes vs class attributes#
Attributes set on self belong to one instance. Attributes defined directly in the class body are class attributes, shared by all instances:
When you read self.pi, Python looks on the instance first, then on the class. Class attributes are great for constants and counters — but never use a mutable class attribute for per-instance data:
The fix: create the list in __init__ with self.items = [].
Printing objects nicely#
By default, printing an object shows something unhelpful like <__main__.Dog object at 0x7f...>. Define __repr__ (for developers) and optionally __str__ (for end users):
A good __repr__ looks like the code that would recreate the object. These double-underscore "dunder" methods are the subject of a whole lesson soon.
"Private" attributes by convention#
Python has no private keyword. Instead, a leading underscore says "internal — don't touch from outside":
Python trusts developers — "we're all consenting adults". Code can still access t._target, but doing so is clearly at your own risk. (Two underscores, __target, trigger name mangling to avoid clashes in subclasses; it's rarely needed.) In the properties lesson you'll see the Pythonic way to add validation without getter/setter methods.
Objects interacting#
Real programs consist of objects that hold and use other objects — called composition:
Common mistakes#
- Forgetting
selfin a method definition:def bark():raisesTypeError: bark() takes 0 positional arguments but 1 was given. - Forgetting
self.when using an attribute:balance += amountinside a method refers to a local variable, not the attribute. - Mutable class attributes used as per-instance state.
- Calling the class without its arguments:
Dog()raisesTypeErrorif__init__requiresnameandage. - Making everything a class. If it's just data, a dict or dataclass might do; if it's just behaviour, a function is fine.
What's next#
Classes can build on other classes. Next: inheritance and polymorphism — reusing and specialising behaviour.
Check your understanding
Quick quiz
1.What is
selfin a method?2.What does
__init__do?3.A class attribute
items = []is defined directly in the class body. What happens when one instance appends toself.items?
Finished reading?
Mark this lesson complete to track your progress.