Б41 Чистый Python. Тонкости программирования для профи. Спб.: Питер



Download 6,94 Mb.
Pdf ko'rish
bet66/80
Sana24.02.2022
Hajmi6,94 Mb.
#212875
1   ...   62   63   64   65   66   67   68   69   ...   80
Bog'liq
978544610803 Chisty Python Tonko

'Привет' 
>>> next(iterator) 
'Привет' 
>>> next(iterator) 
'Привет' 
...
Этот фрагмент кода дает тот же самый результат — бесконечный поток 
приветствий. Всякий раз, когда вы вызываете 
next()
, итератор снова вы-
дает то же самое приветствие.
Между прочим, здесь я воспользовался возможностью замены вызо-
вов 
__iter__
и 
__next__
на вызовы встроенных в Python функций 
iter()
и 
next()
.
На внутреннем уровне эти встроенные функции вызывают те же самые 
дандер-методы, но они делают программный код немного симпатичнее 
и более удобочитаемым, предоставляя протоколу итератора чистый «фа-
сад».
Python предлагает эти фасады также и для другой функциональности. На-
пример, 
len(x)
является краткой формой для вызова 
x.__len__
. Точно так 
же вызов функции 
iter(x)
вызывает метод 
x.__iter__
, а вызов функции 
next(x)
вызывает метод 
x.__next__
.
В целом неплохая идея использовать встроенные фасадные функции, 
вместо того чтобы непосредственно обращаться к дандер-методам, реа-


218 Глава 6 • Циклы и итерации
лизующим протокол итератора. Это намного упрощает восприятие ис-
ходного кода.
Более простой класс-итератор
До этого момента наш пример итератора состоял из двух отдельных клас-
сов, 
Repeater
и 
RepeaterIterator
. Они соответствовали непосредственно 
двум фазам, используемым в протоколе итератора Python: сначала подго-
товке и получению объекта-итератора через вызов функции 
iter()
, а затем 
неоднократной доставке из него значений через вызов функции 
next()
.
Во многих случаях обе эти функциональные обязанности можно взва-
лить на один-единственный класс. Это позволит сократить объем про-
граммного кода, необходимого для написания итератора, основанного 
на классах.
Я решил этого не делать с первым примером в данном разделе, потому что 
это внесло бы путаницу в чистоту ментальной модели в основе протокола 
итератора. Но теперь, когда вы увидели, как писать итератор на основе 
классов более долгим и более сложным способом, давайте потратим еще 
минуту, чтобы упростить то, что у нас есть на данный момент.
Помните, почему нам вновь потребовался класс 
RepeaterIterator
? Он 
был нужен, чтобы принять метод 
__next__
для доставки новых значений 
из итератора. Но место определения метода 
__next__
вовсе не имеет ни-
какого значения. В протоколе итератора имеет значение только то, что 
метод 
__iter__
возвращает любой объект с определенным на нем методом 
__next__
.
Поэтому идея такая: 
RepeaterIterator
без конца возвращает одинаковое 
значение, и он не должен отслеживать никакое внутреннее состояние. 
Что, если вместо этого добавить метод 
__next__
непосредственно в класс 
Repeater
?
Тем самым мы смогли бы целиком избавиться от 
RepeaterIterator
и реа-
лизовать итерируемый объект при помощи одного-единственного класса 
Python. Давайте попробуем! Наш пример с новым и упрощенным итера-
тором выглядит так:


6 .4 . Красивые итераторы 219
class Repeater:
def __init__(self, value):
self.value = value
def __iter__(self):
return self
def __next__(self):
return self.value
Мы только что перешли от двух отдельных классов и десяти строк кода 
всего к одному классу и семи строкам кода. Наша упрощенная реализация 
по-прежнему без проблем поддерживает протокол итератора:
>>> repeater = Repeater('Привет') 
>>> for item in repeater:
... print(item)
Привет 
Привет 
Привет 
...
В подобной оптимизации итератора на основе класса часто есть смысл. По 
сути, большинство пособий Python по итераторам начинается именно так. 
Но я всегда чувствовал, что объяснять итераторы одним-единственным 
классом с самого начала — значит скрывать основные принципы прото-
кола итератора и по этой причине еще больше затруднять его понимание.
Кто же захочет без конца выполнять итерации
На этом этапе у вас уже должно сложиться довольно хорошее понимание 
того, как итератор работает в Python. Но пока что мы реализовывали 
только такие итераторы, которые продолжают выполнять итерации бес-
конечно.
Очевидно, бесконечное повторение не является главным вариантом ис-
пользования итераторов в Python. На самом деле, когда вы обратитесь 
к самому началу этого раздела, то увидите, что в качестве мотивирующего 
примера я использовал приведенный ниже фрагмент кода:


220 Глава 6 • Циклы и итерации
numbers = [1, 2, 3] 
for n in numbers:
print(n)
Вы вправе ожидать, что этот код выведет числа 
1

2
и 
3
, а затем остано-
вится. И вероятно, вы не ожидаете, что он захламит окно вашего терми-
нала, без устали выводя «
3
», пока вы в дикой панике не начнете жать 
на 
Ctrl+C

Пора узнать, как написать итератор, который в итоге прекращает гене-
рировать новые значения вместо выполнения бесконечных итераций, 
потому что это именно то, что обычно делают объекты Python, когда мы 
используем их в цикле 
for…in
.
Сейчас мы напишем еще один класс итератора, который назовем ограни-
ченным повторителем 
BoundedRepeater
. Он будет похож на наш предыду-
щий пример с повторителем 
Repeater
, но на этот раз мы хотим, чтобы он 
останавливался после предопределенного количества повторений.
Давайте задумаемся. Как это сделать? Как итератор сигнализирует о том, 
что он пуст и исчерпал элементы, выдаваемые во время выполнения 
итераций? Возможно, вы думали: «Хм, можно вернуть 
None
из метода 
__next__
, и все».
И знаете, это неплохая идея, но проблема в следующем: что делать, если 
нам нужно, чтобы некий итератор был в состоянии возвращать 
None
в ка-
честве приемлемого значения?
Давайте посмотрим, что для решения этой проблемы делают другие 
итераторы Python. Я создам простой контейнер, список с несколькими 
элементами, а затем буду выполнять его итеративный обход до тех пор, 
пока он не исчерпает элементы, чтобы увидеть, что произойдет:
>>> my_list = [1, 2, 3] 
>>> iterator = iter(my_list)
>>> next(iterator) 

>>> next(iterator) 



6 .4 . Красивые итераторы 221
>>> next(iterator) 

А теперь осторожно! Мы употребили все три имеющихся в списке элемента. 
Следите за тем, что произойдет, если еще раз вызвать метод 
next
итератора:
>>> next(iterator) 

Download 6,94 Mb.

Do'stlaringiz bilan baham:
1   ...   62   63   64   65   66   67   68   69   ...   80




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish