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



Download 6,94 Mb.
Pdf ko'rish
bet63/80
Sana24.02.2022
Hajmi6,94 Mb.
#212875
1   ...   59   60   61   62   63   64   65   66   ...   80
Bog'liq
978544610803 Chisty Python Tonko

ПРИМЕЧАНИЕ: Не забудьте выполнить пересортировку всякий раз, 
# когда добавляется новый элемент, либо используйте 
# bisect.insort(). 
q.sort(reverse=True)
while q:
next_item = q.pop()
print(next_item)
# Результат: 
# (1, 'есть') 
# (2, 'программировать') 
# (3, 'спать') 
heapq — двоичные кучи на основе списка
Данная реализация двоичной кучи обычно подкрепляется обыкновенным 
списком, и она поддерживает вставку и извлечение наименьшего элемента 
за O(log n) время
2
.
1
См. документацию Python «bisect.insort»: 
https://docs .python .org/3 .6/library/bisect .html
2
См. документацию Python «heapq»: 
https://docs .python .org/3 .6/library/heapq .html


5 .7 . Очереди с приоритетом 199
Этот модуль — хороший выбор для реализации очередей с приоритетом 
в Python. Поскольку двоичная куча 
heapq
технически обеспечивает толь-
ко реализацию min-heap (то есть кучи, где значение в любой вершине не 
больше, чем значения ее потомков), должны быть предприняты допол-
нительные шаги, которые обеспечат стабильность сортировки и другие 
функциональные возможности, которые, как правило, ожидают от «прак-
тической версии» очереди с приоритетом
1
.
import heapq
q = []
heapq.heappush(q, (2, 'программировать')) 
heapq.heappush(q, (1, 'есть')) 
heapq.heappush(q, (3, 'спать'))
while q:
next_item = heapq.heappop(q)
print(next_item)
# Результат: 
# (1, 'есть') 
# (2, 'программировать') 
# (3, 'спать') 
queue .PriorityQueue — красивые очереди с приоритетом
Данная реализация очереди с приоритетом во внутреннем представлении 
использует двоичную кучу 
heapq
и имеет одинаковую временную и про-
странственную вычислительную сложность
2
.
Разница состоит в том, что очередь с приоритетом 
PriorityQueue
синхро-
низирована и обеспечивает семантику блокирования с целью поддержки 
многочисленных параллельных производителей и потребителей.
В зависимости от вашего варианта использования она либо станет по-
лезной, либо слегка замедлит вашу программу. В любом случае вы мо-
1
См. документацию Python «Примечания к реализации очереди с приоритетом»: там же.
2
См. документацию Python «queue.PriorityQueue»: 
https://docs .python .org/3 .6/library/queue .
html


200 Глава 5 • Общие структуры данных Python
жете предпочесть интерфейс на основе класса, предлагаемый классом 
PriorityQueue
, использованию интерфейса на основе функций, предла-
гаемого модулем heapq.
from queue import PriorityQueue 
q = PriorityQueue()
q.put((2, 'программировать')) 
q.put((1, 'есть')) 
q.put((3, 'спать'))
while not q.empty():
next_item = q.get()
print(next_item)
# Результат: 
# (1, 'есть') 
# (2, 'программировать') 
# (3, 'спать') 
Ключевые выводы
‰
‰
Python содержит несколько реализаций очередей с приоритетом, ко-
торые вы можете использовать в своих программах.
‰
‰
Реализация 
queue.PriorityQueue
выбивается из общего ряда, отлича-
ясь хорошим объектно-ориентированным интерфейсом и именем, ко-
торое четко указывает на ее направленность. Такая реализация должна 
быть предпочтительным вариантом.
‰
‰
Если требуется избежать издержек, связанных с блокировкой очере-
ди 
queue.PriorityQueue
, то непосредственное использование моду-
ля 
heapq
также будет хорошим выбором.


6
Циклы и итерации
6 .1 . Написание питоновских циклов
Один из самых легких способов отличить разработчика с опытом работы 
на C-подобных языках, который совсем недавно перешел на Python, — по-
смотреть, как он пишет циклы.
Например, всякий раз, когда я вижу фрагмент кода, который выглядит, 
как показано ниже, сразу понимаю, что тут пытались программировать на 
Python так, будто это C или Java:
my_items = ['a', 'b', 'c'] 
i = 0 while i < len(my_items):
print(my_items[i])
i += 1
Итак, вы спрашиваете, что же такого непитоновского в этом фрагменте 
кода?
Две вещи.
Во-первых, в коде вручную отслеживается индекс 
i
— его инициализация 
нулем, а затем постепенное увеличение после каждой итерации цикла.
И во-вторых, в коде используется функция 
len()
, которая получает раз-
мер контейнера 
my_items
, чтобы определить количество итераций.


202 Глава 6 • Циклы и итерации
В Python можно писать циклы, которые справляются с этими двумя за-
дачами автоматически. И будет просто замечательно, если вы возьмете это 
на вооружение. Например, если вашему коду не придется отслеживать на-
растающий индекс, то будет намного труднее написать непреднамеренный 
бесконечный цикл. Это также сделает программный код более сжатым 
и поэтому удобочитаемым.
Чтобы рефакторизовать первый пример кода, я начну с того, что удалю 
фрагмент, который вручную обновляет индекс. В Python лучше всего для 
этого применить цикл 
for
. При помощи встроенной фабричной функции 
range()
я могу генерировать индексы автоматически:
>>> range(len(my_items)) 
range(0, 3)
>>> list(range(0, 3)) 
[0, 1, 2]
Тип 
range
представляет неизменяемую последовательность чисел. Его 
преимущество перед обычным списком 
list
в том, что он всегда занимает 
одинаково небольшое количество оперативной памяти. Объекты-диапа-
зоны в действительности не хранят отдельные значения, представляющие 
числовую последовательность, вместо этого они функционируют как 
итераторы и вычисляют значения последовательности на ходу
1
.
Поэтому, вместо того чтобы на каждой итерации цикла вручную увели-
чивать индекс 
i
, я смог воспользоваться функцией 
range()
и написать 
что-то подобное:
for i in range(len(my_items)):
print(my_items[i])
Уже лучше. Однако этот вариант по-прежнему выглядит не совсем по-
питоновски и ощущается больше как итеративная Java-конструкция, а не 
как настоящий цикл Python. Когда вы видите программный код, в кото-
1
Чтобы получить такое экономное для оперативной памяти поведение в Python 2, вам 
придется использовать встроенную функцию 
xrange()
, так как функция 
range()
будет 
в действительности конструировать объект-список.


6 .1 . Написание питоновских циклов 203
ром для итеративного обхода контейнера используется 
range(len(...))

его, как правило, можно еще больше упростить и улучшить.
Как я уже отмечал, циклы 
for
в Python в действительности являются 
циклами «for each», которые могут выполнять непосредственный пере-
бор элементов контейнера или последовательности без необходимости 
искать их по индексу. И этот факт я могу задействовать для дальнейшего 
упрощения этого цикла:
for item in my_items:
print(item)
Я считаю такое решение вполне питоновским. В нем применено несколько 
продвинутых функциональных средств Python, но при этом оно остается 
хорошим и чистым и читается почти как псевдокод из учебника по про-
граммированию. Обратите внимание, что в этом цикле больше не отсле-
живается размер контейнера, а для доступа к элементам не используется 
нарастающий индекс.
Теперь контейнер сам занимается раздачей элементов для их обработки. 
Если контейнер упорядочен, то и результирующая последовательность 
элементов будет такой же. Если контейнер не упорядочен, он будет воз-
вращать свои элементы в произвольном порядке, но цикл по-прежнему 
охватит их все полностью.
Нужно сказать, что, конечно, вы не всегда будете в состоянии переписать 
свои циклы таким образом. А что, если, например, вам нужен индекс 
элемента?
Для таких случаев есть возможность писать циклы, которые поддержива-
ют нарастающий индекс, избегая применения шаблона с 
range(len(...))

от которого я вас предостерег. Встроенная функция 
enumerate()
поможет 
вам сделать подобного рода циклы безупречными и питоновскими:
>>> for i, item in enumerate(my_items):
... print(f'{i}: {item}') 
0: a 
1: b 
2: c


204 Глава 6 • Циклы и итерации
Дело в том, что итераторы в Python могут возвращать более одного зна-
чения. Они могут возвращать кортежи с произвольным числом значений, 
которые затем могут быть распакованы прямо внутри инструкции 
for
.
Это очень мощное средство. Например, тот же самый прием можно исполь-
зовать, чтобы в цикле одновременно перебрать ключи и значения словаря:
>>> emails = {
... 'Боб': 'bob@example.com',
... 'Алиса': 'alice@example.com',
... }
>>> for name, email in emails.items():
... print(f'{name} -> {email}')

Download 6,94 Mb.

Do'stlaringiz bilan baham:
1   ...   59   60   61   62   63   64   65   66   ...   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