Python Instance Method: Definition and Usage
python instance method: Learn how Python instance methods work, how the self parameter binds methods to objects, and when to choose instance, class, or static methods.
python instance method requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
What an Instance Method Is
In Python, an instance method is a function defined inside a class that operates on a specific object of that class. When you call obj.method(), Python passes obj as the first argument, conventionally named self, so the method can read and modify that object's attributes.
class Counter: def __init__(self, start=0): self.value = start def increment(self, step=1): self.value += step return self.value
Here increment is an instance method. It receives the Counter instance as self and updates self.value. Two different Counter objects keep separate value attributes, so calling increment on one does not affect the other.
a = Counter() b = Counter(10) a.increment() b.increment(5) print(a.value) # 1 print(b.value) # 15
The method body never refers to a global counter; it always operates on the instance that was passed in. That is the defining property of an instance method: its behavior depends on the state of one particular object.
How self Binds the Method to the Instance
The binding happens at attribute access time. When you write a.increment, Python looks up increment on the class and finds a function object. Because functions implement the descriptor protocol, the lookup wraps the plain function into a bound method that carries the instance along. The bound method stores both the function and the instance, so calling it supplies the instance automatically.
You can observe this directly:
print(Counter.increment) # <function Counter.increment at ...> print(a.increment) # <bound method Counter.increment of ...>
Counter.increment is a plain function. a.increment is a bound method. That is why a.increment() works while Counter.increment() raises a TypeError about a missing self argument.
This binding also means you can store the bound method and call it later without remembering which object it belongs to:
increment_a = a.increment increment_a()
The bound method keeps its reference to a, so the call still updates the correct instance even when the original variable goes out of scope.
Instance Methods vs Class Methods vs Static Methods
Python has three kinds of methods, distinguished by the first argument they receive.
| Method type | First argument | Receives | Typical use |
|---|---|---|---|
| Instance method | self | The instance | Read or modify instance state |
| Class method | cls | The class | Factory methods, class-level configuration |
| Static method | none | nothing | Utility logic that needs no class or instance state |
A class method is decorated with @classmethod and receives the class rather than an instance. A static method is decorated with @staticmethod and receives no automatic first argument at all.
class Temperature: scale = "Celsius" def __init__(self, value): self.value = value def to_fahrenheit(self): return self.value * 9 / 5 + 32 @classmethod def from_fahrenheit(cls, value): celsius = (value - 32) * 5 / 9 return cls(celsius) @staticmethod def is_valid(value): return value > -273.15
to_fahrenheit is an instance method because it needs self.value. from_fahrenheit is a class method because it creates a new instance and should work correctly even when called on a subclass. is_valid is a static method because it only checks the argument and touches neither instance nor class state.
The decision rule is straightforward: use an instance method when the behavior depends on the specific object's state. Use a class method when the behavior depends on the class or must construct instances. Use a static method when the logic is independent of both.
Mutating and Reading Instance State
Instance methods are the primary mechanism for encapsulating state changes. A well-designed instance method keeps the internal representation private and exposes a clear operation.
class BankAccount: def __init__(self, owner, balance=0.0): self.owner = owner self._balance = balance def deposit(self, amount): if amount <= 0: raise ValueError("deposit amount must be positive") self._balance += amount return self._balance def withdraw(self, amount): if amount <= 0: raise ValueError("withdrawal amount must be positive") if amount > self._balance: raise ValueError("insufficient funds") self._balance -= amount return self._balance @property def balance(self): return self._balance
Here deposit and withdraw are instance methods that validate input and then modify self._balance. The leading underscore signals that _balance is internal; callers interact with it through the balance property or the mutation methods. This keeps the validation logic in one place instead of duplicating it at every call site.
Instance methods can also return computed values without mutating anything. A method that only reads state is still an instance method if it needs the instance's attributes.
Common Mistakes When Defining Instance Methods
The most frequent error is forgetting the self parameter. A method defined without self raises a TypeError when called on an instance, because Python still tries to pass the instance as the first argument.
class Broken: def greet(): return "hello" b = Broken() b.greet() # TypeError: takes 0 positional arguments but 1 was given
The fix is to accept self even when the method does not use it, or to make the method static if it genuinely needs no instance state.
Another common mistake is naming an instance attribute the same as a method. Because instance attributes take precedence over class attributes during lookup, the attribute shadows the method and the call fails or behaves unexpectedly.
A third mistake is calling the method on the class rather than on the instance. Counter.increment() fails because there is no instance to pass. Calling Counter.increment(a) works because it passes a explicitly, but normal code should use a.increment().
Runtime Behavior and Attribute Lookup
Instance method calls involve attribute lookup on the instance, then on the class, then on parent classes. When you write a.increment, Python first checks a.__dict__ for an increment attribute. If the instance does not define one, the lookup continues on the class and its bases, where it finds the function and binds it.
This lookup order matters when an instance attribute shadows a method name:
class Example: def run(self): return "method" e = Example() e.run = lambda: "shadowed" print(e.run()) # shadowed
Assigning e.run creates an instance attribute that shadows the class method. The method is still available on the class, but the instance-level attribute wins during lookup. This is rarely intentional, but it explains why naming collisions between attributes and methods cause confusing behavior.
The binding step itself creates a new bound method object on each attribute access. For hot loops that call the same method millions of times, storing the bound method once can reduce allocation overhead.
method = a.increment for _ in range(1_000_000): method()
This avoids creating a fresh bound method object on every iteration. The difference is usually small, but it is measurable in tight loops and is a legitimate micro-optimization when profiling shows the call site matters.
Choosing Between Instance, Class, and Static Methods
The choice is not about style; it affects how the code behaves under inheritance and how callers interact with it.
Use an instance method when the behavior reads or modifies attributes of a specific object, when the method needs to be polymorphic per instance, or when subclasses should override it and receive the subclass instance.
Use a class method when the behavior needs the class itself, such as a factory that must return cls(...) so subclasses construct themselves correctly, or when the behavior modifies class-level state shared across all instances.
Use a static method when the logic is purely a function of its arguments, when the method does not need to be overridden per instance or per class, and when the class is used only as an organizational container.
A common mistake is making a method static simply because the current body does not use self. That works until a later change needs instance state, at which point every call site must be updated. Prefer an instance method when the method conceptually belongs to the object, even if the current implementation does not yet read any attributes.