Найти - Пользователи
Полная версия: Задача по шифрованию текста
Начало » Python для новичков » Задача по шифрованию текста
1 2
py.user.next
indiwiduum
Есть какой-то лайфхак это обойти?
Если тебе нужен прямо .remove() внутри цикла, то for надо заменить на while. Сделать там индекс там и прочее. Тогда оно не будет ничего съедать. Ты просто поленился, сделал такой удобный for, который там всё сам перебирает, а он работает через итератор, который создаёт в фоне. А в итераторе назад ходить нельзя. Если элемент ты взял из итератора, то всё, этот элемент обратно в итератор вернуть нельзя. А в цикле while, где контроль по индексу идёт, можно всё это делать.
AD0DE412
 import itertools
# extreme
text = 'aaaabbсaa'
print(''.join([''.join([i[0], str(len(list(i[1])))]) for i in itertools.groupby(text)]))
# and ultimate
print(''.join(map(lambda x: x[0] + str(len(list(x[1]))), itertools.groupby(text))))
ps py.user.next ну если вы взялись об'снять за циклы то уж разкажите про протокол next
py.user.next
AD0DE412
то уж разкажите про протокол next
Есть глобальные функции iter() и next(). Функция iter() создаёт итератор и возвращает его. А функция next() к существующему итератору применяет операцию “взять следующий элемент” и возвращает этот элемент полученный. Когда итератор заканчивается, функция next() порождает исключение StopIteration. Оно внутри итератора возникает, переходит функции next(), а функция next() его уже наружу проводит.

Так вот цикл for эту функцию iter() вызывает неявно, а потом он так же неявно вызывает функцию next() для неявно полученного итератора. Таким образом, если ты элементы удалил какие-то впереди, то все элементы впереди сдвинутся, а цикл for на следующем шаге вызовет так же эту функцию next() и возьмёт только элемент, который там следующий по очереди по расчётам итератора. Но итератор их просто считает и знает, какой элемент следующий по счёту; он не следит, как они там удаляются без его участия. Итератор, например, их посчитал “я уже три элемента видел и вернул, а следующий элемент четвёртый”. А ты берёшь и четвёртый удаляешь, а вместо четвёртого пятый элемент ставишь. А итератор всё так же считает “я вижу четвёртый элемент, я его возвращаю, следующий будет пятый элемент”. То есть итератор не понимает, что элементы поменялись в количестве, поэтому он думает, что пятый элемент - это четвёртый, что шестой элемент - это пятый.

Дальше, что такое протокол итератора. Функции iter() и next() обращаются к методам __iter__() и __next__(). Функция iter() ищет метод __iter__() у объекта, чтобы получить из этого метода итератор. А функция next() ищет метод __next__() у итератора, чтобы получить следующий элемент или исключение StopIteration.

Любой объект, который у себя реализовал метод __iter__(), становится итерируемым - то есть способным построить итератор по запросу из функции iter() и вернуть его.
Любой объект, который у себя реализовал метод __next__(), становится итератором - то есть способным взять элемент по запросу из функции next() и вернуть его.

Пример
  
>>> text = 'abc'
>>> 
>>> text.__iter__
<method-wrapper '__iter__' of str object at 0x7facc4b00ae8>
>>> 
>>> text.__next__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__next__'
>>> 
>>> it = iter(text)
>>> it
<str_iterator object at 0x7facbc979710>
>>> 
>>> it.__iter__
<method-wrapper '__iter__' of str_iterator object at 0x7facbc979710>
>>> 
>>> it.__next__
<method-wrapper '__next__' of str_iterator object at 0x7facbc979710>
>>> 
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> 
>>> itit = iter(it)
>>> itit
<str_iterator object at 0x7facbc979710>
>>>
>>> itit.__iter__
<method-wrapper '__iter__' of str_iterator object at 0x7facbc979710>
>>>
>>> itit.__next__
<method-wrapper '__next__' of str_iterator object at 0x7facbc979710>
>>> 
>>> next(itit)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>
Как видим, у строки есть метод __iter__(), поэтому для неё можно построить итератор. При этом строка не является итератором сама по себе, потому что у неё нет метода __next__().
Когда мы построили итератор для строки, мы получили объект, у которого есть метод __next__(). Также у этого объекта есть метод __iter__(), чтобы для итератора можно было построить новый итератор. При этом, как показывает практика, обычно метод __iter__() у итератора возвращает ссылку на сам этот итератор, то есть итератор возвращает сам себя. Но это и необязательно, можно и что-то новое возвращать.

Пример
  
>>> class A:
...     def __iter__(self):
...         self.n = 0
...         return self
...     def __next__(self, default=None):
...         if self.n < 3:
...             self.n += 1
...             return 'nothing'
...         else:
...             raise StopIteration
... 
>>> a = A()
>>> a
<__main__.A object at 0x7fce57bf9748>
>>> 
>>> it = iter(a)
>>> it
<__main__.A object at 0x7fce57bf9748>
>>> 
>>> next(it)
'nothing'
>>> next(it)
'nothing'
>>> next(it)
'nothing'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in __next__
StopIteration
>>> 
>>> for i in A():
...     print(i)
... 
nothing
nothing
nothing
>>>
AD0DE412
офигенно
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