Найти - Пользователи
Полная версия: Dive into python не понятно
Начало » Python для новичков » Dive into python не понятно
1 2
dobriy_dada
Здравствуйте, подскажите пожалуйста в книге 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 ? Подскажите пожалуйста :-)
py.user.next
dobriy_dada
как может индекс быть меньше, если он увеличивается перед добавлением в список self.cache ?
Он для второго прохода так сделан. При первом проходе правила кешируются и остаются для последующих проходов. При следующем проходе сначала просматривается кеш, пока в нём не закончатся правила, а потом продолжается чтение правил из файла (с добавлением их в кеш).
dobriy_dada
Спасибо, теперь начинает доходить :-)
То есть допустим мы определили множественное число для первого слова, а для второго слова кэш с функциями (self.cache) уже заполнен, и строка
if len(self.cache) >= self.cache_index:
позволяет нам брать функции из кэша, а не читая файл. Правильно? :-)
py.user.next
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
dobriy_dada
Спасибо, теперь начинает доходить :-)
Не меняй сообщения, которые написал, иначе теряется линия беседы.
Думаешь, я помню все разговоры наизусть? Да я уже забыл, что ты говорил пять минут назад, потому что таких собеседников десяток.
dobriy_dada
спасибо :-)
endless_lama
Вопрос по тому же коду, а именно к вот этой части:

 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? Зачем нужно его каждый раз ресетить?

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

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

Например:
У тебя есть три слова, которые надо обработать, каждое по своему правилу.
Для первого слова подходит десятое правило. Ты десять правил прочитал и закешировал, а последнее из них ещё вернул наружу и преобразовал по нему первое слово.
Для второго слова подходит пятое правило. В кеше есть десять правил, поэтому из файла читать уже ничего не надо. Ты с начала кеша дошёл до пятого правила, вернул его наружу и преобразовал по нему второе слово.
Для третьего слова подходит двадцатое правило. Сначала ты проходишь весь кеш и понимаешь, что там этого правила нет. Тогда ты продолжаешь читать файл и читаешь ещё десять правил из него и кешируешь их. Когда двадцатое правило прочитано и закешировано, ты его возвращаешь наружу и преобразовываешь по нему третье слово.
Теперь у тебя в кеше двадцать правил, а в файле осталось ещё десять правил. Любое следующее слово теперь будет искать сначала в кеше среди двадцати правил подходящее. При этом в файле есть ещё правила, если этих двадцати правил в кеше не хватит. Когда весь файл будет прочитан, все правила будут только в кеше. Но если у тебя сто слов, для которых нужно только первое правило, то из файла будет прочитано только первое правило, а дальше все слова будут преобразованы по правилу из кеша. То есть файл вообще читаться не будет, только одно правило прочитает из него и всё.
endless_lama
Большое спасибо за подробное объяснение! То есть self.cache_index = 0 значит, что “указатель” кеша сбрасывается на начало кеша? Или значит, что кеш пустой? Я вот это не очень понимаю..
py.user.next
endless_lama
То есть self.cache_index = 0 значит, что “указатель” кеша сбрасывается на начало кеша?
Любой итератор работает так: сначала его надо построить, потом можно получать из него элементы.
Чтобы построить итератор по объекту, у объекта запускается метод __iter__(). А чтобы получить любой элемент, у построенного итератора запускается метод __next__().
Индекс кеша в данном случае устанавливается на ноль только при построении итератора. Дальше любой элемент получается из итератора без обнуления индекса кеша.

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

Все правила перечитываются с самого начала для каждого нового слова.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB