Methods, Attributes & self
You'll learn to
- -Distinguish instance attributes (per-object) from class attributes (shared across all instances)
- -Explain the mutable-class-attribute gotcha and how to avoid it
- -Explain why self.total += 1 on a class attribute does not update the class counter
- -Understand the difference between calling obj.method() and referencing Class.method
You have already been using instance attributes (self.count, self.balance), values that belong to one specific object. This chapter covers the other kind of attribute a class can have, class attributes, and clears up exactly what self and .method() mean under the hood.
An Analogy: The Office Notice Board and Desk Drawers
An office has one notice board on the wall that everybody reads. Each person also has their own desk drawer. Putting a notice on the board changes it for everyone. Putting a sticky note on your own desk only changes what you see: you still read your note first, but the board on the wall is unchanged and your colleagues never see it.
- -The notice board is a class attribute: one copy, shared by every instance.
- -A desk drawer is an instance attribute: each object has its own.
- -The sticky note that covers the board for one person is an instance attribute that shadows a class attribute.
Instance Attributes vs. Class Attributes
An attribute set with self.x = ... inside a method belongs to that one instance. An attribute defined directly in the class body, not inside any method, is a class attribute. It is shared by every instance of the class, unless a specific instance overrides it.
The rule behind it is the lookup order. When you read r1.factory_name, Python looks at the instance's own attributes first and the class second. After r1.factory_name = "Independent Corp", r1's own attributes are {'name': 'Unit-1', 'factory_name': 'Independent Corp'}, so r1 finds its own value first. r2's attributes are just {'name': 'Unit-2'}, so r2 still falls through to the class, and Robot.factory_name is unchanged.
This is the class-level version of the mutable default argument bug from the previous module. If a class attribute is a mutable object like a list, every instance shares that same list unless each __init__ explicitly creates its own with self.items = [].
A Quiet Bug: self.total += 1
The same lookup order causes a very common bug. A class attribute is meant to count instances, and __init__ does self.total += 1. That line reads the class value, adds one, and then assigns the result to self.total, which creates a new instance attribute and leaves the class attribute untouched:
What obj.method() Actually Does
When you write account.deposit(50), Python translates this behind the scenes into BankAccount.deposit(account, 50). The object you called the method on is automatically passed as the first argument, self. This is exactly why every instance method's signature starts with self: it is a placeholder for "whichever object this gets called on."
- -Class attributes are useful for genuinely shared, read-mostly data, like a constant, or a counter of how many instances exist.
- -Anything that should differ per instance, and especially anything mutable, belongs in __init__ as self.something.
- -obj.method(args) and Class.method(obj, args) do the same thing; the dot syntax is just more convenient sugar.
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.
Discussion0
Join the Discussion
Sign in to leave comments, reply to others, or like insights.
No comments yet. Be the first to start the thread!