Цель возвращения self python

у меня проблема с return self

class Fib: 
    def __init__(self, max):
        self.max = max
    def __iter__(self): 
        self.a = 0
        self.b = 1
        return self
    def __next__(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

Я уже видел этот вопрос возвращение проблемы с собой но я не могу понять, в чем польза return self?

2 ответов


возвращение self метод просто означает, что ваш метод возвращает ссылку на экземпляр объекта, на который он был вызван. Это иногда можно увидеть в использовании с объектно-ориентированными API, которые разработаны как свободно интерфейс что побуждает метод каскадного. Так, например,

>>> 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()

теперь мы можем использовать каскадный метод:

>>> c.increment().increment().decrement()
<__main__.Counter object at 0x1020c1390>

обратите внимание на последний вызов decrement() вернулся <__main__.Counter object at 0x1020c1390>, которым и self. Теперь:

>>> c.val
2
>>>

обратите внимание, вы не можете сделать это, если вы не вернули 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 "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'increment'
>>> c
<__main__.Counter object at 0x1020c15f8>
>>> c.val
2
>>>

обратите внимание, не все являются поклонниками "каскадного метода" дизайна. Встроенные Python не имеют тенденцию делать это, поэтому,list например:

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

вы do часто вижу это, когда ваш класс реализует iterator протоколу, где iter на итератор возвращает self по соглашению, хотя это предложено документы:

увидев механику за протоколом итератора, легко добавьте поведение итератора в свои классы. Определите __iter__() способ который возвращает объект с __next__() метод. Если класс определяет __next__(), потом __iter__() может просто вернуться 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]

обратите внимание, что это фактически делает ваш итератор полезным только для одного прохода:

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

это бесполезно сложный код. Не обращайте на это внимания. На земле нет причин реализовывать его таким образом.

Это, как говорится, то, что он делает это:

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

Это все гораздо проще выразить как:

def fib(max_):
    a, b = 0, 1
    while b <= max_:
        out = a
        a, b = b, a+b
        yield out

примеры:

>>> 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