Skip to main content

How to Understand return self in Python Class Methods

The return self statement in a Python class method serves two primary purposes: enabling method chaining and implementing the iterator protocol.

This guide explains both use cases, providing clear examples and guidelines for when (and when not) to use return self.

Method Chaining with return self

Method chaining allows you to call multiple methods on the same object in a single, continuous expression. This can make code more readable and concise, especially when performing a sequence of related operations on an object. return self is the key to enabling this pattern. Without return self (or returning some other object that you want to continue working with), the chain breaks.

class Calc():
def __init__(self, number=0):
self.number = number

def add(self, value):
self.number = self.number + value
return self # Return the object itself

def subtract(self, value):
self.number = self.number - value
return self # Return the object itself

def display(self): # A method that DOESN'T return self
print(self.number)

calc = Calc()
calc.add(5).subtract(2).add(5) # Method chaining
print(calc.number) # Output: 8

calc.subtract(5).add(3) # Chaining works in any order
print(calc.number) # Output: 6

# Example showing the difference with a method that DOESN'T return self:
calc.add(5).display() # Output: 11
# calc.add(5).display().subtract(2) # ⛔️ AttributeError: 'NoneType' object has no attribute 'subtract'
  • return self: Each method (add and subtract) modifies the object's state (self.number) and then returns the object itself (self).
  • Chaining: Because each method returns the object, you can immediately call another method on the result. calc.add(5) returns the calc object, so you can then call .subtract(2) on it, and so on. This creates a "fluent interface."
  • display() Doesn't Return self: The display() method prints the value but doesn't return anything (implicitly returns None). You can't chain further method calls after display(). This illustrates the importance of return self for chaining.

A More Illustrative Example

Consider a class representing a string builder:

class StringBuilder:
def __init__(self):
self.string = ""

def append(self, text):
self.string += text
return self

def prepend(self, text):
self.string = text + self.string
return self

def to_string(self): # Doesn't return self
return self.string

builder = StringBuilder()
result = builder.append("Hello").append(", ").prepend("Greetings: ").to_string()
print(result) # Output: Greetings: Hello,

This example is more practical. StringBuilder lets you build up a string piece by piece. The append and prepend methods return self, allowing chaining. The to_string() method returns the final string (and therefore doesn't return self).

Implementing the Iterator Protocol with return self

The second major use of return self is in the __iter__() method of a class to make it iterable.

class Counter:
def __init__(self, start, stop):
self.current = start - 1 # Start one *before* the desired starting value
self.stop = stop

def __iter__(self):
return self # Return the object itself (THIS IS THE KEY)

def __next__(self):
self.current += 1 # Increment the counter
if self.current < self.stop:
return self.current # Return the next value
raise StopIteration # Signal the end of iteration


for c in Counter(0, 4): # You can use the class directly in a loop
print(c)

Output:

0
1
2
3
  • __iter__(self): This method is called when an iterator is requested for the object (e.g., at the start of a for loop). It must return an iterator object. In many cases (including this one), the object is its own iterator, so we return self.
  • __next__(self): This method is called to get the next item in the sequence. It raise StopIteration when there are no more items. This is how the loop knows when to stop.
  • Key Point: In an iterator, the __iter__() method almost always return self.

When NOT to Use return self

  • Methods that return a specific value: If a method's purpose is to compute and return a specific result (e.g., a calculation, a boolean, a new object), don't return self. Return the actual result.
  • Methods with no logical return value: If a method's primary purpose is to modify the object's state, and it doesn't have a meaningful value to return, then a simple return (without any value), or even no return statement at all, is perfectly fine. Python implicitly returns None in this case. Don't return self just for the sake of it.

Example

def do_math(a,b):
return a+b # Returns the sum of the arguments.

result = do_math(5, 5)
print(result) # Output: 10

def print_value(val):
print(val)
return # No logical return value, so we return None.

Conclusion

The return self statement in Python class methods has two important, distinct uses:

  1. Method Chaining: return self allows you to create a fluent interface, making code more readable and concise when performing a sequence of operations on an object.
  2. Iterator Protocol: In the __iter__() method of a class, return self is the standard way to indicate that the object itself is its own iterator.

Use return self strategically and appropriately, and avoid it when a method has a different logical return value or no return value at all. This will make your code clearer and easier to maintain.