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
- -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.
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.
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 = []`.
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 (a constant, 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.