Python return self function

Python return self function

Last updated: Feb 22, 2023
Reading time · 2 min

banner

# Purpose of ‘return self’ from a class method in Python

The purposes of the return self statement from a class method are:

  1. The ability to chain multiple calls to a method because return self returns the instance object.
  2. Using the iterator protocol, which requires us to return self from the __iter__() method.
Copied!
class Calc(): def __init__(self, number=0): self.number = number def add(self, value): self.number = self.number + value return self def subtract(self, value): self.number = self.number - value return self calc = Calc() calc.add(5).subtract(2).add(5) print(calc.number) # 👉️ 8 calc.subtract(5).add(3) print(calc.number) # 👉️ 6

purpose of return self in class method

The add and subtract methods in the Calc() class use a return self statement.

When we call an instance method, Python automatically passes self as the first argument to the method.

self represents an instance of the class — the instance on which the method was called.

When we return self from a class method, we basically return the instance object.

This allows us to chain multiple calls to the method in a single statement.

# Chaining multiple calls to a method that returns self

The add() and subtract() methods return the instance, so we can chain many calls to the methods in a single line, without storing the results in intermediary variables.

Copied!
class Calc(): def __init__(self, number=0): self.number = number def add(self, value): self.number = self.number + value return self def subtract(self, value): self.number = self.number - value return self calc = Calc() calc.add(5).subtract(2).add(5) print(calc.number) # 👉️ 8

chaining multiple calls to method that returns self

You aren’t going to see the pattern of method chaining often, but some libraries make use of it.

The idea is that each method returns an object, which allows the calls to be chained together in a single statement without storing the results in intermediary variables.

When you see syntax such as obj.a().a().b() , the code under the hood uses the method chaining pattern.

However, returning self from class methods is much more common when implementing the iterator protocol.

The _ _ iter _ _ () method must return the iterator object itself.

Here is an example of how to make a class iterable by implementing the __iter__() method.

Copied!
class Counter: def __init__(self, start, stop): self.current = start - 1 self.stop = stop def __iter__(self): # 👇️ return `self` here return self def __next__(self): self.current += 1 if self.current self.stop: return self.current raise StopIteration for c in Counter(0, 4): print(c) # 👉️ 0, 1, 2, 3

making a class iterable

The __iter__() method is implicitly called at the start of loops and returns the iterator object ( self ).

The __next__() method is implicitly called at each loop increment and returns the next value.

# Additional Resources

You can learn more about the related topics by checking out the following tutorials:

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.

Источник

Purpose of return self python

Returning self from a method simply means that your method returns a reference to the instance object on which it was called. This can sometimes be seen in use with object oriented APIs that are designed as a fluent interface that encourages method cascading. So, for example,

>>> class Counter(object): . def __init__(self, start=1): . self.val = start . def increment(self): . self.val += 1 . return self . def decrement(self): . self.val -= 1 . return self . >>> c = Counter() 

Now we can use method cascading:

>>> c.increment().increment().decrement()

Notice, the last call to decrement() returned , which is self . Now:

Notice, you cannot do this if you did not return self :

>>> class Counter(object): . def __init__(self, start=1): . self.val = start . def increment(self): . self.val += 1 . # implicitely return `None` . def decrement(self): . self.val -= 1 . # implicitely return `None` . >>> c = Counter() >>> c.increment().increment() Traceback (most recent call last): File "", line 1, in AttributeError: 'NoneType' object has no attribute 'increment' >>> c >>> c.val 2 >>> 

Notice, not everyone is a fan of «method cascading» design. Python built-ins do not tend do this, so, list for example:

>>> x = list() >>> x.append(1).append(2) Traceback (most recent call last): File "", line 1, in AttributeError: 'NoneType' object has no attribute 'append' >>> 

The one place you do often see this is when your class implements the iterator protocol, where iter on an iterator returns self by convention, although this is suggested by the docs:

Having seen the mechanics behind the iterator protocol, it is easy to add iterator behavior to your classes. Define an __iter__() method which returns an object with a __next__() method. If the class defines __next__() , then __iter__() can just return self :

class Reverse: """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def __next__(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index] 

Notice, this in effect makes your iterator only useful for a single pass (as it should be to properly follow the iterator protocol):

>>> x = [1, 2, 3, 4] >>> it = iter(x) >>> list(it) [1, 2, 3, 4] >>> list(it) [] >>> next(it) Traceback (most recent call last): File "", line 1, in StopIteration >>> 

This is needlessly complex code. Pay little attention to it. There’s no reason on earth to implement it this way.

That being said, what it does is this:

class Fib: """Implements the Fibonacci sequence.""" def __init__(self, max_): self.max = max_ def __iter__(self): """Initializes and returns itself as an iterable.""" self.a = 0 self.b = 1 return self def __next__(self): """What gets run on each execution of that iterable.""" fib = self.a if fib > self.max: raise StopIteration self.a, self.b = self.b, self.a + self.b # increment return fib 

This is all much easier to express as:

def fib(max_): a, b = 0, 1 while b  
>>> fib_obj = Fib(20) >>> for n in fib_obj: . print(n) >>> for n in Fib(20): . print(n) >>> for n in fib(20): . print(n) # all give. 0 1 1 2 3 5 8 13 

Источник

Читайте также:  Удалить кнопки telebot python
Оцените статью