Страницы

Поиск по вопросам

Показаны сообщения с ярлыком генераторы. Показать все сообщения
Показаны сообщения с ярлыком генераторы. Показать все сообщения

пятница, 6 марта 2020 г.

Атрибут __next__ не переопределяется

#python #python_3x #генераторы #динамическая_типизация


У меня есть класс в котором я переопределяю метод __next __ после его первого вызова,
но проблема в том что работать продолжает старый __next __.

class I:
    def __init__(self, head):
        self.head = iter(head)

    def __iter__(self):
        return self

    def __next__(self):
        self.__next__ = self.head.__next__
        return 'a'


i = I((1, 2, 3))
i_it = iter(i)
print(next(i_it)) #выводит 'a'. Все ок
print(next(i_it)) #снова 'a'. Почему не 1?
print(i_it.__next__) #
вроде __next__ переопределен 


P.S Если переопределять что-то другое то все работает:

    def __next__(self):
        self.__next__ = self.head.__next__
        self.x = 1
        return 'a'


После вызова next(self) x будет 1.
Ссылка на онлайн компилятор: https://repl.it/HVOC/17

P.P.S: В коментариях говорят что если вызывать i_it.__next __() то все будет работать
так как надо, я это знаю, но штука в том что в любом итераторе(цикл for например) работает
next(self), а не self.__next __().
    


Ответы

Ответ 1



На сколько я понимаю, в cpython встроенная функция next() определяется тут: builtin_next(). Можно увидеть, что при вызове имеется следующая конструкция: res = (*it->ob_type->tp_iternext)(it); Полагаю, что она равносильна примерно такой конструкции на Python: next(i) --> i.__class__.__next__(i) что сходится с тем, что видно на практике. Как дела происходят в других интерпретаторах мне не известно.

Ответ 2



Сначала i_it.__next__ = i.__next__. Затем i.__next__ = self.head.__next__ Но i_it.__next__ остался прежним, тк его не меняли. Те __next__ был изменен только для объекта класса i, но не для итератора i_it

среда, 22 мая 2019 г.

Атрибут __next__ не переопределяется

У меня есть класс в котором я переопределяю метод __next __ после его первого вызова, но проблема в том что работать продолжает старый __next __.
class I: def __init__(self, head): self.head = iter(head)
def __iter__(self): return self
def __next__(self): self.__next__ = self.head.__next__ return 'a'
i = I((1, 2, 3)) i_it = iter(i) print(next(i_it)) #выводит 'a'. Все ок print(next(i_it)) #снова 'a'. Почему не 1? print(i_it.__next__) # вроде __next__ переопределен
P.S Если переопределять что-то другое то все работает:
def __next__(self): self.__next__ = self.head.__next__ self.x = 1 return 'a'
После вызова next(self) x будет 1. Ссылка на онлайн компилятор: https://repl.it/HVOC/17
P.P.S: В коментариях говорят что если вызывать i_it.__next __() то все будет работать так как надо, я это знаю, но штука в том что в любом итераторе(цикл for например) работает next(self), а не self.__next __().


Ответ

На сколько я понимаю, в cpython встроенная функция next() определяется тут: builtin_next(). Можно увидеть, что при вызове имеется следующая конструкция:
res = (*it->ob_type->tp_iternext)(it);
Полагаю, что она равносильна примерно такой конструкции на Python:
next(i) --> i.__class__.__next__(i)
что сходится с тем, что видно на практике.
Как дела происходят в других интерпретаторах мне не известно.