Classes and objects
A class is a blueprint: it says what attributes (data) and methods (functions) every object of that kind has. An object is one instance built from it. __init__ runs when an object is created and sets up its attributes. self is the object the method was called on — Python passes it automatically, which is why every method's first parameter is self.
You should see
Ada 153.0
BankAccount True
{'owner': 'Ada', 'balance': 153.0}withdraw(amount) method that refuses to overdraw, and a second account. Confirm the two balances are independent.class BankAccount:def __init__(self, owner, balance=0):self.owner = ownerself.balance = balancedef deposit(self, amount):self.balance += amountacct = BankAccount("Ada", 100)acct.deposit(50)
Calling the class creates an empty object, then calls __init__(new_object, "Ada", 100). self is that new object.
self | <BankAccount> |
All 5 steps as a table
| Step | Line | What happened | Variables now |
|---|---|---|---|
| 1 | 9 | Calling the class creates an empty object, then calls __init__(new_object, "Ada", 100). self is that new object. | self = <BankAccount> |
| 2 | 3 | Set an attribute on the object: self.owner = "Ada". | self.owner = 'Ada' |
| 3 | 4 | self.balance = 100. __init__ returns; the finished object is bound to acct. | self.balance = 100 acct = <BankAccount> |
| 4 | 10 | acct.deposit(50) is sugar for BankAccount.deposit(acct, 50) — the object goes in as self, 50 as amount. | amount = 50 |
| 5 | 7 | Read self.balance (100), add 50, store it back on the same object. | self.balance = 150 |
TypeError: deposit() takes 1 positional argument but 2 were given
class BankAccount:
def deposit(amount): # forgot self
print("depositing", amount)
BankAccount().deposit(50)Traceback (most recent call last):
File "your code", line 5, in <module>
BankAccount().deposit(50)
TypeError: BankAccount.deposit() takes 1 positional argument but 2 were givenPython always passes the object as the first argument. Your method declared one parameter (amount), so the object filled it and the 50 had nowhere to go. Whenever an argument count is off by exactly one inside a class, it is a missing self.
Add self as the first parameter of every method.
class BankAccount:
def deposit(self, amount):
print("depositing", amount)
BankAccount().deposit(50)AttributeError: 'BankAccount' object has no attribute 'balence'
class BankAccount:
def __init__(self):
self.balance = 0
acct = BankAccount()
print(acct.balence)Traceback (most recent call last):
File "your code", line 6, in <module>
print(acct.balence)
AttributeError: 'BankAccount' object has no attribute 'balence'. Did you mean: 'balance'?The object has no attribute by that name. A typo, or an attribute that __init__ only sets on some code path, or — very often — a method you forgot to call with parentheses and then tried to use as a value. The famous variant is 'NoneType' object has no attribute …: something returned None and you kept going (Module 11).
Check the spelling against __init__; use dir(acct) or acct.__dict__ to see what actually exists.
class BankAccount:
def __init__(self):
self.balance = 0
acct = BankAccount()
print(acct.balance)