Python
self argument
Python methods
object-oriented programming
Python duplicate

Why do you need explicitly have the self argument in a Python method?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Python instance methods require an explicit first parameter, usually named self. This design can look unusual if you come from languages where instance context is implicit. In practice, explicit self makes method binding transparent and keeps Python function semantics simple.

How Instance Method Binding Works

A method defined inside a class starts as a regular function object stored on the class. When you access it through an instance, Python creates a bound method object that carries the instance reference.

python
1class Counter:
2    def __init__(self):
3        self.value = 0
4
5    def increment(self, step):
6        self.value += step
7        return self.value
8
9c = Counter()
10print(c.increment(3))

Calling c.increment(3) is conceptually similar to calling Counter.increment(c, 3). That is why the first parameter must exist.

Explicit self Improves Readability

Because self is explicit, you can immediately see which names are instance attributes and which are local variables.

python
1class User:
2    def __init__(self, name):
3        self.name = name
4
5    def rename(self, name):
6        old_name = self.name
7        self.name = name
8        return old_name, self.name

Without explicit self, assignments to instance state would be less obvious in large methods.

Descriptor Protocol Behind the Scenes

Python method binding is implemented through the descriptor protocol. Functions implement __get__, which decides what is returned when accessed from class or instance.

python
1class Demo:
2    def show(self):
3        return "instance method"
4
5print(Demo.show)         # function on class
6obj = Demo()
7print(obj.show)          # bound method with obj attached

That mechanism is consistent with other descriptors such as property, which is one reason Python keeps method binding explicit and uniform.

self Versus cls Versus Static Methods

Instance methods receive self, class methods receive cls, and static methods receive neither unless you pass one manually.

python
1class Example:
2    kind = "demo"
3
4    def instance_method(self):
5        return f"instance kind: {self.kind}"
6
7    @classmethod
8    def class_method(cls):
9        return f"class kind: {cls.kind}"
10
11    @staticmethod
12    def static_method(x, y):
13        return x + y
14
15ex = Example()
16print(ex.instance_method())
17print(Example.class_method())
18print(Example.static_method(2, 5))

Choosing the right method type clarifies how much object state is required.

Why Python Did Not Hide It

Python favors explicit behavior and minimal hidden magic. Requiring self means the language does not need a special keyword for instance scope, and plain functions remain the foundation for methods.

This also helps metaprogramming. Because methods are just functions plus descriptor behavior, decorators and dynamic method assignment remain straightforward. It also makes unit tests clearer when calling methods directly through the class with explicit instance arguments.

Common Pitfalls

A common beginner mistake is forgetting the first parameter entirely, which causes argument count errors when calling the method. The fix is to define the instance parameter explicitly.

Another issue is naming the first parameter something other than self. Python allows it, but teams should keep self for readability and tooling consistency.

A third issue is using instance methods where static methods are better. If no instance state is read or modified, @staticmethod communicates intent more clearly.

Finally, confusion between class and instance attributes can lead to unexpected shared state. Use self.attribute for per instance data and ClassName.attribute for class wide constants.

Summary

  • Methods are functions that become bound to an instance at access time
  • Explicit self makes data ownership and mutation clear
  • Counter.increment(c, step) is the conceptual model behind method calls
  • Use cls for class methods and no implicit first parameter for static methods
  • Keeping self explicit supports Python readability and metaprogramming flexibility
  • Consistent self usage improves code review speed and team conventions

Course illustration
Course illustration

All Rights Reserved.