Decoding the Error
It is one of the most common "gotchas" for developers transitioning to Object-Oriented Programming in Python. You call a method with a single value, but Python insists you provided two. The resulting traceback usually looks like this:
Traceback (most recent call last):
File "app.py", line 12, in <module>
account.deposit(500)
TypeError: deposit() takes 1 positional argument but 2 were given
The Logic Behind the "Missing" Argument
In 99% of cases, this error happens because you forgot the self parameter in your class method definition. When you call a method on an object instance, Python automatically passes that instance as the very first argument. It does this work behind the scenes so your objects can track their own state.
Take a look at this broken example:
class BankAccount:
def deposit(amount): # Missing 'self'!
print(f"Depositing ${amount}")
account = BankAccount()
account.deposit(500)
Even though you only typed 500 inside the parentheses, Python actually executes the call like this: BankAccount.deposit(account, 500). Since your function was defined to only accept one thing (amount), the addition of the account object creates a mismatch.
Three Ways to Fix It
1. The Standard Fix: Adding 'self'
If your method needs to modify or read data from the object—like changing a user's email or a bank balance—you must include self. It acts as a placeholder for whichever specific object is calling the function.
Fixed Code:
class BankAccount:
def __init__(self):
self.balance = 0
# 'self' is the first parameter, 'amount' is the second
def deposit(self, amount):
self.balance += amount
print(f"New balance: ${self.balance}")
account = BankAccount()
account.deposit(500) # Works perfectly now
2. The Utility Fix: Using @staticmethod
Sometimes a function belongs inside a class for organization, but it doesn't actually need to touch any object data. In these cases, use the @staticmethod decorator. This tells Python: "Don't pass the instance to this function."
class ToolBox:
@staticmethod
def convert_to_usd(amount, rate):
return amount * rate
tb = ToolBox()
# No 'self' is passed, so 2 arguments stay 2 arguments
print(tb.convert_to_usd(100, 1.1))
3. The Class-Level Fix: Using @classmethod
Use @classmethod if you need to access the class itself rather than a specific instance. Instead of self, the first argument becomes cls. This is common for creating "factory" methods that generate new objects.
class User:
def __init__(self, name):
self.name = name
@classmethod
def from_guest_account(cls):
return cls("Guest") # 'cls' refers to the User class
new_user = User.from_guest_account()
Verifying the Solution
Run your script again after adding self. If you are fixing an instance method, a quick way to verify it is to check if an attribute actually updated. For our bank example, printing account.balance after the call confirms the logic is flowing correctly. If the error persists, double-check that self is truly the first parameter in the list.
Pro-Tips for Clean Code
- The Name is a Rule: You could technically call
selfsomething else, likethisorme, but you shouldn't. Stick toselfto ensure other developers can read your code without a headache. - Check the Constructor: The
__init__method is the most frequent place people forgetself. If you miss it there, your code will crash the moment you try to create a new object. - Mind Your Decoration: If you find yourself writing a method that never uses
self, it's a strong signal that it should probably be a@staticmethod.

