Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 5, 2016 20:59:50

dobriy_dada
Зарегистрирован: 2015-09-04
Сообщения: 48
Репутация: +  0  -
Профиль   Отправить e-mail  

Dive into python не понятно

Здравствуйте, подскажите пожалуйста в книге Dive into python есть пример создания итератора в файле plural6.py , код там такой

def __init__(self):
        self.pattern_file = open(self.rules_filename, encoding='utf-8')
        self.cache = []
    def __iter__(self):
        self.cache_index = 0
        return self
    def __next__(self):
        self.cache_index += 1
        if len(self.cache) >= self.cache_index:
            return self.cache[self.cache_index - 1]
        if self.pattern_file.closed:
            raise StopIteration
        line = self.pattern_file.readline()
        if not line:
            self.pattern_file.close()
            raise StopIteration
        pattern, search, replace = line.split(None, 3)
        funcs = build_match_and_apply_functions(
            pattern, search, replace)
        self.cache.append(funcs)
        return funcs
Непонятно что обозначает выражение
if len(self.cache) >= self.cache_index:
            return self.cache[self.cache_index - 1]
Что оно выполняет, как может индекс быть меньше, если он увеличивается перед добавлением в список self.cache ? Подскажите пожалуйста :-)

Офлайн

#2 Янв. 6, 2016 00:50:35

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10003
Репутация: +  857  -
Профиль   Отправить e-mail  

Dive into python не понятно

dobriy_dada
как может индекс быть меньше, если он увеличивается перед добавлением в список self.cache ?
Он для второго прохода так сделан. При первом проходе правила кешируются и остаются для последующих проходов. При следующем проходе сначала просматривается кеш, пока в нём не закончатся правила, а потом продолжается чтение правил из файла (с добавлением их в кеш).



Отредактировано py.user.next (Янв. 6, 2016 00:53:14)

Офлайн

#3 Янв. 6, 2016 08:32:15

dobriy_dada
Зарегистрирован: 2015-09-04
Сообщения: 48
Репутация: +  0  -
Профиль   Отправить e-mail  

Dive into python не понятно

Спасибо, теперь начинает доходить :-)
То есть допустим мы определили множественное число для первого слова, а для второго слова кэш с функциями (self.cache) уже заполнен, и строка

if len(self.cache) >= self.cache_index:
позволяет нам брать функции из кэша, а не читая файл. Правильно? :-)

Отредактировано dobriy_dada (Янв. 6, 2016 09:53:18)

Офлайн

#4 Янв. 6, 2016 10:01:31

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10003
Репутация: +  857  -
Профиль   Отправить e-mail  

Dive into python не понятно

dobriy_dada
Допустим, что при первом проходе будет следующее:
Это не проход, проход - это когда ты весь итератор исчерпал, взяв все его элементы.

Вот пример с двумя проходами
>>> class A:
...     def __iter__(self):
...         self.it = iter('abc')
...         return self
...     def __next__(self):
...         return next(self.it)
... 
>>> a = A()
>>> 
>>> it = iter(a)
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __next__
StopIteration
>>> 
>>> it = iter(a)
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __next__
StopIteration
>>>

Вот то же самое
>>> class A:
...     def __iter__(self):
...         self.it = iter('abc')
...         return self
...     def __next__(self):
...         return next(self.it)
... 
>>> a = A()
>>> 
>>> for i in a:
...     i
... 
'a'
'b'
'c'
>>> for i in a:
...     i
... 
'a'
'b'
'c'
>>>

Видишь, итератор (итерабельный объект) один, а проходов по нему два.



Отредактировано py.user.next (Янв. 6, 2016 10:07:38)

Офлайн

#5 Янв. 6, 2016 10:11:41

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10003
Репутация: +  857  -
Профиль   Отправить e-mail  

Dive into python не понятно

dobriy_dada
Спасибо, теперь начинает доходить :-)
Не меняй сообщения, которые написал, иначе теряется линия беседы.
Думаешь, я помню все разговоры наизусть? Да я уже забыл, что ты говорил пять минут назад, потому что таких собеседников десяток.



Офлайн

#6 Янв. 6, 2016 13:17:16

dobriy_dada
Зарегистрирован: 2015-09-04
Сообщения: 48
Репутация: +  0  -
Профиль   Отправить e-mail  

Dive into python не понятно

спасибо :-)

Офлайн

#7 Ноя. 24, 2017 10:05:01

endless_lama
Зарегистрирован: 2017-11-24
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Dive into python не понятно

Вопрос по тому же коду, а именно к вот этой части:

 def __iter__(self):
        self.cache_index = 0
        return self

В книге написано так: "The for loop in the plural() function will call iter(rules), which will reset the cache index but will not reset the open file object."

Но я не очень понимаю, зачем нужно, чтобы self.cache_index = 0? Зачем нужно его каждый раз ресетить?

Заранее спасибо за ответ!

Отредактировано endless_lama (Ноя. 24, 2017 10:05:49)

Офлайн

#8 Ноя. 24, 2017 11:46:18

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10003
Репутация: +  857  -
Профиль   Отправить e-mail  

Dive into python не понятно

endless_lama
Но я не очень понимаю, зачем нужно, чтобы self.cache_index = 0? Зачем нужно его каждый раз ресетить?
Этот итератор достаёт правила из файла. Когда он достаёт правило, он его записывает в кеш. А тому, кто использует этот итератор, нужно получить первое подходящее правило. То есть может получиться ситуация, где нужное правило находится в середине файла. После того как правило найдено, итератор отбрасывается и больше не используется.

И вот тут у нас появляется необходимость второй раз перебрать все правила. Тогда этот итератор снова берётся, но в нём есть закешированные правила. Кеш работает быстрее, чем чтение из файла, а указатель файла стоит где-то в середине файла. Поэтому мы сначала ищем правило в кеше (ведь там может оказаться нужное правило), а если оно не найдено там, то мы продолжаем читать файл и кешировать правила дальше.

Например:
У тебя есть три слова, которые надо обработать, каждое по своему правилу.
Для первого слова подходит десятое правило. Ты десять правил прочитал и закешировал, а последнее из них ещё вернул наружу и преобразовал по нему первое слово.
Для второго слова подходит пятое правило. В кеше есть десять правил, поэтому из файла читать уже ничего не надо. Ты с начала кеша дошёл до пятого правила, вернул его наружу и преобразовал по нему второе слово.
Для третьего слова подходит двадцатое правило. Сначала ты проходишь весь кеш и понимаешь, что там этого правила нет. Тогда ты продолжаешь читать файл и читаешь ещё десять правил из него и кешируешь их. Когда двадцатое правило прочитано и закешировано, ты его возвращаешь наружу и преобразовываешь по нему третье слово.
Теперь у тебя в кеше двадцать правил, а в файле осталось ещё десять правил. Любое следующее слово теперь будет искать сначала в кеше среди двадцати правил подходящее. При этом в файле есть ещё правила, если этих двадцати правил в кеше не хватит. Когда весь файл будет прочитан, все правила будут только в кеше. Но если у тебя сто слов, для которых нужно только первое правило, то из файла будет прочитано только первое правило, а дальше все слова будут преобразованы по правилу из кеша. То есть файл вообще читаться не будет, только одно правило прочитает из него и всё.



Отредактировано py.user.next (Ноя. 24, 2017 11:57:48)

Офлайн

#9 Ноя. 24, 2017 16:02:35

endless_lama
Зарегистрирован: 2017-11-24
Сообщения: 7
Репутация: +  0  -
Профиль   Отправить e-mail  

Dive into python не понятно

Большое спасибо за подробное объяснение! То есть self.cache_index = 0 значит, что “указатель” кеша сбрасывается на начало кеша? Или значит, что кеш пустой? Я вот это не очень понимаю..

Отредактировано endless_lama (Ноя. 24, 2017 16:02:59)

Офлайн

#10 Ноя. 25, 2017 01:33:24

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10003
Репутация: +  857  -
Профиль   Отправить e-mail  

Dive into python не понятно

endless_lama
То есть self.cache_index = 0 значит, что “указатель” кеша сбрасывается на начало кеша?
Любой итератор работает так: сначала его надо построить, потом можно получать из него элементы.
Чтобы построить итератор по объекту, у объекта запускается метод __iter__(). А чтобы получить любой элемент, у построенного итератора запускается метод __next__().
Индекс кеша в данном случае устанавливается на ноль только при построении итератора. Дальше любой элемент получается из итератора без обнуления индекса кеша.

endless_lama
Или значит, что кеш пустой?
Кеш никогда не опустошается, только растёт. Но чтобы читать из него правила для каждого нового слова (а это нужно делать каждый раз с самого начала), индекс кеша ставится на начало кеша.

Все правила перечитываются с самого начала для каждого нового слова.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version