59 рекомендаций по написанию
эффективного кода
Effective Python
59 Specific Ways to Write Better Python
Brett Slatkin
•
'У'У
A<i<lisoп-Wesley
Бретт Слаткин
•
Москва ·Санкт-Петербург· Киев
2016
ББК32.973.26-018.2.75
С47
УДК681.3.07
Издательский дом "Вильяме"
Тhавный редактор С.Н. Три.губ
Зав. редакцией В.Р. Гинзбург
Перевод с английского и редакция канд. хим. наук А.Г. Гузикевича
По общим вопросам обращайтесь в Издательский дом ивильямс" по адресу:
info@williamspuЬlishing.com, http: / /www.williamspuЬlishing.com
Слаткив. Бретт.
С4 7 Секреты Python: 59 рекомендаций по написанию эффективного
кода.: Пер. с англ. - М.: ООО ии.д. Вильяме", 2016. - 272 с.: ил. -
Парал. тит. англ.
ISBN 978-5-8459-2078-2 (рус.)
:ввк 32.973.26-018.2.75
Все названия программных продуктов .являются зарегистрированными торговыми марка
ми соответствующих фирм.
Никакая часть настоящего издания ни в каких цел.ях не может быть воспроизведена в ка
кой бы то ни было форме и какими бы то ни было средствами. будь то электронные или меха
нические. включая фотокопирование и запись на магнитный носитель. если на это нет пись
менного разрешения издательства Addison-Wesley PuЬlishing Company. Inc.
Authoгized Russiaп traпslation of the English edition of E.ffectlve Python: 59 specific шауs to
wri.te Ьetter Python (ISBN 978-0-13-403428-7) © 2015 Pearson Education. Inc.
Тhis traпslation is puЬlished and sold Ьу pennission of Peachplt Press, which owns or controls
all rlghts to puЫish and sell the same.
All rights reseIVed. No part of this book may Ье reproduced or transmitted in any fonn or Ьу any
means. electronlc or mechanical, lncluding photocopylng. recording, or Ьу any lnfonnatloп storage
or retrieval system, without the prior wrltten pennission of the copyrtght owner and the PuЬlisher.
Об авторе 13
Введение 14
ГJiава 1. Мыслим категориями языка Python 19
ГJiава 2. Функции 53
ГJiава 3. Классы и наследование 83
ГJiава 4. Метаклассы и атрибуты 119
Г.Лава 5. Одновременность и параJIJiелизм 151
Г.Лава 6. Встроенные модули 189
Г.Лава 7. Совместная работа 217
Г.Лава 8. Производство 245
Предметный указатель 267
С одер3tаиие
Об авторе 13
Введевне 14
О чем эта книга 14
Соглашения , принятые в книге 16
!Де найти код примеров 17
Ждем ваших отзывов! 18
Гпава 2. Функции 53
Рекомендация 1 4 . Использование исключений предпочтительнее
возврата значения None 53
Рекомендация 1 5 . Знайте , как замыкания взаимодействуют
с областью видимости переменных 56
Рекомендация 1 6. Не упускайте возможность использовать
генераторы вместо возврата списков 61
Рекомендация 1 7. Не забывайте о мерах предосторожности при
итерировании аргументов 64
Рекомендация 1 8 . Снижайте визуальный шум с помощью пере-
менного количества позиционных аргументов 69
Рекомендация 1 9. Обеспечивайте опциональное поведение
с помощью именованных аргументов 71
Рекомендация 20. Используйте значение None и средство
Docstrings при задании динамических значе-
ний по умолчанию для аргументов 75
Рекомендация 2 1 . Повышайте ясность кода, используя именован-
ные аргументы 78
"Будь у меня под рукой эта книга тогда. когда я решился перейти с Java
на Python. это помогло бы мне сэкономить массу времени . которое я по
тратил на многократное переписывание кода, что происходило всякий
раз . когда я осознавал. что делаю что-то "не в духе Python" . В книге со
браны крупицы тех основных сведений . которые обязан знать каждый
программист на языке Python. чтобы не спотыкаться о них на протя
жении многих месяцев и даже лет работы, учась на собственных ошиб
ках. Широта охватываемых тем просто поражает. Важность следования
принципам РЕР8 . основные идиомы Python. проектирование функций .
методов и классов , эффективное использование стандартной библиоте
ки . проектирование качественного API . тестирование программ и изме
рение производительности кода - обо всем этом вы сможете прочитать
в книге. Фантастический материал. представляющий действительную
ценность для любого программиста на языке Python. независимо от
того. новичок он или опытный разработчик" .
Майк Бейер, создатель фреймворка SQIЛlchemy
"Это замечательная книга как для новичков . так и для опытных про
граммистов . Примеры кода тщательно продуманы. а соответствующие
пояснения отличаются краткостью и ясностью" .
Чарльз Титус Браун. адъюнкт-профессор. Калифорнийский университет
вДейвисе
Гл:ава 2. Функции
Функции в языке Python обладают целым рядом дополнительных
особенностей . облегчающих жизнь программистам. Некоторые из них
имеют аналоги в других языках. но многие свойственны только Python .
Эта глава посвящена использованию функций для раскрытия наме
рений программиста . содействия повторному использованию кода и
уменьшения вероятности того. что в него вкрадутся ошибки.
Гпава8. Проиэводство
В языке Python предусмотрены средства адаптации к широкому кру
гу сред развертывания. Он также включает встроенные модули. наце
ленные на повышение надежности и защищенности программ . В этой
главе обсуждаются предлагаемые в Python средства отладки. оптимиза
ции и тестирования. предназначенные для улучшения качества и про
изводительности программ.
»>
sys . v e r s ion_info ( maj o r = З , m i n o r=4, m i c ro= 2 ,
� relea se leve l = ' f i na l ' , s e r i a l=0 )
З . 4 . 2 ( defa u lt , Oct 19 2014, 17 : 5 2 : 17 )
� [GCC 4 . 2 . 1 Compa t i Ь l e Apple L LVM 6 . 0 ( c la n g - 600 . 0 . 5 1 ) )
Примечание
Средство Pylint (http:/ /www . pyl int . org/) - это популярный статический анали
затор исходного кода на языке Python. Pylint обеспечивает автомати ческое обнару
жение отклонен и й стиля оформлен ия кода от ста нда ртов РЕР 8 и выявляет многие
другие ти п ы распростра ненных ошибок в п рограммах на языке Python.
>>>
Type E r ro r : must Ье st r , n ot byt e s
)))
{ ' red ' : [ ' 5 ' ] , ' green ' : [ ' ' ] , ' Ы u е ' : [ ' 0 ' ] }
»>
Красный : ['5']
З еленый : [' ']
Непроз рачность : None
>»
К р а с ный : '5'
З еленый : 0
Непрозрачность : 0
if fou n d [ 0 ] :
found = i nt ( found [ 0 ] )
else :
found = defa u lt
ret u r n fou n d
»>
Первые ч етыре : [ 'а', 'ь', 'с1 , 'd' ]
Посл едн и е четыре : [ , е , , ' f ' , g ' , ' h ' ]
1
а [20 ]
»>
I n d ex E r ro r : l i st i n d ex out of range
Примечание
Имейте в виду, что и ндексирова н ие списка отрицательными значени ями перемен
ной - оди н из немногих случаев, в которых извлечен ие среза может при водить к
неожида н н ы м результатам. Напри мер, выражение somel i s t [ - п : ] будет отлично
работать, если п больше еди ницы (например, s ome l i s t [ - 3 : ] ). Но при нулевом зна
чении п вы ражение some l i s t [ - 0 : ] создает коп и ю исходного списка.
Результатом извлечения среза из списка является совершенно новый
список. Ссьmки на объекты исходного списка сохраняются. Изменение
результата извлечения среза никак не сказывается на исходном списке.
Ь = а [4 : ]
p r i nt ( ' До : Ь)
b [l ] = 99
p r i nt ( ' Пocлe : Ь)
p r i nt ( ' Бeз изменен и й : ' , а )
>>>
До : ['е', 'f' , 'g' , 'h' ]
После : [ ' е ' , 99, ' g ' , ' h ' ]
Без и зменен и й : [ ' а ' , ' Ь ' , ' с ' , ' d ' , ' е ' , ' f ' , ' g ' , ' h ' ]
»>
до : ['а', 'Ь', 'с', 'd' , 'е' , 'f' , 'g' , 'h' ]
Посл е : [ ' а ' , ' Ь ' , 9 9 , 2 2 , 14, ' h ' ]
»>
до : [ ' а ' , ' Ь ' , 9 9 , 2 2 , 14, ' h ' ]
После : [ 10 1 , 102 , 103 ]
p rint ( odd s )
p r i nt ( even s )
»>
[ ' red ' , ' ye l l ow ' , ' Ы u е ' ]
( ' o ra nge ' , ' green ' , ' p u rp l e ' ]
>»
b ' e soognom '
х w . e n c od e ( ' ut f - 8 ' )
у х ( : : -1]
z = y . d e c od e ( ' utf - 8 ' )
»>
U n i c odeDe c od e E rror : ' utf - 8 ' codec c a n ' t decode byt e 0x9d i n
� pos ition 0 : inva l i d s t a rt byt e
»>
[ 1 , 4 , 9 , 1 6 , 2 5 , 3 6 , 49 , 64, 8 1 , 100 ]
»>
[4 , 16, 3 6 , 64 , 100 )
>»
{ 1 : · ghost ' , 2 : ' h a b a n e ro ' , 3 : ' c ay e n n e · }
{8, 5 , 7}
>>>
[ 1 , 2 , 3 , 4 , 5, 6 , 7 , 8 , 9 ]
>>>
[ [ 1 , 4 , 9 ] , [ 16 , 2 5 , 3 6 ] , [ 49 , 64, 8 1 ] ]
»>
[ [б] , (9) )
»>
[ 100 , 5 7 , 1 5 , 1 , 1 2 , 7 5 , 5 , 8 6 , 89, 1 1 ]
»>
< generator obj ect < ge n e x p r > at 0х101Ь81480 >
»>
100
57
>»
( 1 5 , 3 . 872983 346207417 )
При итерировании п о списку вам часто надо будет знать также ин
декс текущего элемента. Предположим , например, что вы хотите выве
сти рейтинг ваших любимых сортов мороженого . Один из возможных
способов сделать это заключается в использовании функции ran g e ( ) .
for i i n range ( l e n ( flavor_l ist ) ) :
flavor = flavor_l i st [ i ]
p r i nt ( ' %d : %s ' % ( i + 1 , flavo r ) )
»>
1: ваниль
2: ш о колад
З: пекан
4: земл я н и ка
»>
Cec ilia
Проблема в том , что вся эта конструкция цикла в целом выглядит до
вольно громоздко. Индексы в names и letters затрудняют чтение кода.
Индексирование массивов с помощью индекса цикла i происходит
дважды. Использование функции en umerate ( ) (см. предьщущую реко
мендацию) немного улучшает сиrуацию, но она все еще остается неиде
альной .
for i , n ame in e n umerat e ( name s ) :
count = lett e r s [ i ]
if c o u nt > max_lett e r s :
longe st_n ame = name
max_lett e r s = c o u nt
»>
Cec i l i a
Lise
Ma rie
Новый элемент для ' Ros a l i n d ' здесь отсутствует. Это произошло про
сто потому. что так работает функция z i p ( ) . Она возвращает кортежи
до тех пор , пока обернутый ею итератор не будет исчерпан . Такой под
ход отлично работает, если вам известно, что все итераторы имеют одну
и ту же длину, как это часто имеет место в случае производных списков ,
создаваемых генераторами . Во многих других случаях вы можете стол
кнуться с неожиданным и нежелательным поведением этой функции .
когда она урезает вывод. Если у вас нет уверенности в том, что длина
списков , которые вы планируете обработать с помощью функции z i p ( ) .
одинакова, попробуйте использовать вместе нее функции z i p_longe st ( )
(izip_longest ( ) в Python 2) из встроенного модуля itertool s .
»>
Ци кл 0
Ц и кл 1
Ци кл 2
Блок Else !
р r i пt ( ' Бл ок E l s e ! ' )
»>
Ци кл 0
Цикл 1
»>
Блок For E l s e !
»>
Бл ок W h i l e E l s e !
»>
Т е с т и руется 2
Тестируется З
Тестирует с я 4
Вза имно п ростые
БJiоки f i n a l ly
Используйте инструкцию t ry/fi n a l ly , если хотите предоставить ис
ключению возможность распространяться, но при этом намерены ос
вободить ресурсы, даже если возникло исключение. Одно из обычных
применений инструкции t ry/fi n a l ly надежное закрытие дескрип
-
Блоки еlsе
Используйте инструкцию t ry/except / e l s e для того , чтобы четко ука
зать, какие исключения будут обрабатываться вашим кодом, а какие -
распространяться . Блок e l s e будет выполняться только в том случае,
если в блоке t ry не возникли исключения. Блок e l s e позволяет миними
зировать объем кода блока t ry и улучшить его удобочитаемость. Пред
положим , например , что вам необходимо загрузить данные словаря в
формате JSON из строки и возвратить значения содержащихся в ней
ключей .
d ef loa d_j son_key ( d ata , key ) :
t ry :
r e s u lt_d ict = j son . load s ( d at a ) # Может г е н е р и ровать
# и с ключ е н и е Va l u e E r ror
exc ept V a l u e E r ro r as е :
r a i s e Key E rror from е
else :
ret u rn r e s u lt_d i ct [ key ] # Может г е н е р и ровать
# и с ключ е н и е Key E rror
UNDE F I N E D = o b j e c t ( )
»>
Резул ьтат : 2 . 5
»>
[ 2 , З , 5 , 7 , 1 , 4, б, 8 ]
Есть три причины, по которым эта функция работает так , как ожида
ется .
+ Язык Python поддерживает замыкан.ия - функции , ссьmающиеся
на переменные из области видимости, в которой они бьmи опре
делены. Вот почему функция h e l p e r ( ) способна получать доступ
к аргументу group функции so rt_p riori ty ( ) .
Фуикцвв 57
»>
На йдено : F a l s e
[2, 3, 5, 7, 1 , 4, 6, 8]
58 ГJiава 2
щий получить тот же результат. который перед этим бьш получен с по
мощью нелокальной переменной. Размер кода при этом немного увели
чивается, но читать его легче (более подробно о специальном методе _
d e f _c a l l_ ( s e l f , х ) :
if х i n self . group :
self . found = True
ret u rn (0, х )
ret u rn ( 1 , х )
Для тестовых входных данных эта функция работает так. как и сле
довало ожидать.
62 Гяава 2
»>
[ 0 , 5 , 11 ]
»>
[ 11 . 5 3 8461 5 38461 5 3 8 , 26 . 92 3076923076923 , 61 . 5 3 8461 5 3 846154]
for l i n e i n f :
yield i nt ( l i n e )
»>
[]
»>
( 1 5 , 3 5 , 80 ]
[]
»>
[ 11 . 5 3 846 1 5 3 8461 5 3 8 , 26 . 9 23076923076923 , 61 . 5 3 846 1 5 3 8461 5 4 ]
При таком подходе проблемой остается то, что размер копий содер
жимого входного итератора может быть очень большим. Копирование
итератора способно привести к перерасходу памяти и краху програм
мы. Один из способов обойти эту трудность заключается в том , чтобы
принимать функцию, которая возвращает новый итератор всякий раз ,
когда она вызывается .
d ef n o rma l i z e_fu n c ( get_it e r ) :
t ot a l = s u m ( get_it e r ( ) ) # Новый итератор
r e s u lt = [ ]
for v a l u e in get_it e r ( ) : # Новый итератор
percent = 100 * v a l u e / tot a l
r e s u lt . a ppend ( pe r c ent )
ret u r n res u lt
def �it e r� ( s e l f ) :
with open ( s elf . da t a_pat h ) a s f :
for l i n e i n f :
y i e l d int ( l i n e )
»>
[ 1 1 . 53846 1 5 3 846 1 5 3 8 , 26 . 9 2307692307692 3 , 61 . 5 3846 1 5 3 8461 54]
for v a l u e i n numbe r s :
percent = 100 * v a l u e / t ot a l
re s u lt . appen d ( p e r c e nt )
ret u rn res u lt
>»
Type E rror : Долже н п р едос тавлять ся конте й н е р
»>
Любимые цвета : 7 , 3 3 , 99
it = my_ge n e rator ( )
my_fu n c ( * it )
»>
( 0 , 1, 2, 3 , 4 , 5 , 6, 7, 8 , 9)
»>
1 : Любимые : 7 , 33
Любимые ч и сла : 7 : 3 3
a s s e rt rema ind e r { 20 , 7 ) == 6
>>>
»>
Type E r ro r : rema i n de r ( ) got mult i p l e v a l u e s for a rgument
� ' n umbe r '
weight_d iff = 0 . 5
t ime_d iff = З
flow = flow_rate ( weight_d iff , t i me_d iff )
print ( ' % . Зf к г в с е кунду ' % f low )
>»
0 . 167 к г в с екунду
Примечание
Обеспечение обратной совместимости за счет использован и я необязател ьных и ме
нованных параметров имеет критически важное значение для фун кций, принима ю
щих переменное количество аргументов (см. п редыдущую рекомендаци ю). Но еще
лучше всегда использовать а р гументы, которые должны указываться только как
именован н ые (раздел "Рекомендация 2 1 . Повыша йте ясность кода, используя име
нованные а ргументы").
»>
201 5 - 1 1 - 1 5 2 1 : 10 : 10 . 3 7 143 2 : При вет !
201 5 - 1 1 - 1 5 2 1 : 10 : 10 . 37143 2 : Еще раз п р и вет !
Args :
me s s age : Выводимое с ообще н и е .
when : Дата и время г е н е р а ц и и с ообще н и я .
По умол ч а н ию - текущи е дата и время .
>»
201 5 - 1 1 - 1 5 2 1 : 10 : 10 . 47 2 303 : При вет !
201 5 - 1 1 - 1 5 21 : 10 : 10 . 5 7 3 39 5 : При вет еще раз !
»>
Foo : { ' st uff ' : 5 , ' meep ' : 1 }
Ba r : { ' stuff ' : 5 , ' meep ' : 1 }
Args :
data : J SОN - да нные , п одл ежащие де коди рова н и ю .
d efa u lt : Возвраща емое з н а ч е н и е п р и н еудач н ом
де коди ров а н и и .
По умол ч а н ию - пустой словар ь .
if defa u l t i s Non e :
d efa u lt = { }
t ry :
78 Гяава 2
ret u r n j so n . load s ( da t a )
exc ept Va l u e E r ro r :
ret u r n defau lt
»>
F oo : { ' stuff ' : 5 }
Ba r : { ' me ep ' : 1 }
»>
0.0
>»
inf
»>
Type E r ror : safe_d iv i s i on_c ( ) t a k e s 2 po s i t io n a l a rgument s but
� 4 were given
t ry :
safe_d i v i s ion_c { l , 0 )
exc ept Ze roDivi s i o n E rror :
p a s s # Как и ожидало с ь
Функции 81
»>
Поз ицион ные : ( 1 , 2 )
Именова н ные : { ' foo ' : ' b a r ' , ' st uff ' : ' meep ' }
safe_d i v i s ion_d ( l . 0 , 10 )
safe_d i v i s ion_d ( l . 0 , 0 , igno re_z e ro_d i v i s ion=Tru e )
safe_d i v i s ion_d ( l . 0 , 1 0 * * 500 , igno re_ove rf low= T ru e )
»>
Type E r ror : s afe_d i v i s ion_d ( ) t a k e s exa c t ly 2 a rgument s
( 4 given )
>»
Type E rror : Неожида н ные * * kwargs : { ' u n expected ' : T r u e }
s e l f . _grade s [ n ame ] = ( ]
def average_grad e ( s e l f , n a me ) :
grades = s e l f . _grad es [ n ame ]
ret u rn s um ( grades ) / l e n ( gra d e s )
»>
90 . 0
В то время как для метода repo rt_g rade ( ) потребовались самые не
значительные изменения (значением стал кортеж) . в методе average_
grade ( ) появился цикл в цикле, в результате чего читаемость кода ухуд
шилась.
def avera ge_grad e ( s e l f , n ame ) :
by_s u b j e c t = s e l f . _grad e s [ n ame ]
s c ore_s u m , s c o re_count = 0 , 0
for s u bj ect , s c o r e s i n by_s u b j ect . it ems ( ) :
s u bj ect_avg, tota l_we ight = 0, 0
for s c o r e , weight i n s c o r e s :
# • • •
grades = [ ]
grades . a ppend ( ( 9 5 , 0 . 45 , ' G reat j ob ' ) )
# • • •
def average_grade ( se lf ) :
tot a l , count = 0 , 0
fo r s u b j ect i n s e l f . _s u b j ect s . va l u e s ( ) :
t ot a l + = s u b j ect . ave rage_grade ( )
c o u nt += 1
ret u r n tot a l / count
d ef s t u d e nt ( s e l f , name ) :
if n a me n ot i n s elf . student s :
s e l f . _student s [ n ame ] = Student ( )
ret u r n s e lf . _student s [ name ]
Кп:ассы в в асяедов авве 89
»>
81 . 5
names = [ ' Soc rat e s ' , ' Ar c h imed e s ' , ' P lato ' , ' Ar i stot l e ' ]
names . so rt ( key = l ambda х : l e n ( x ) )
p rint ( name s )
»>
[ ' Plato ' , ' Soc rat e s ' , ' A r i stot l e ' , ' Ar c h ime d e s ' ]
»>
до : { ' green ' : 1 2 , ' Ы u е ' : З }
Добавлен ключ
Добавлен ключ
После : { ' orange ' : 9, ' green ' : 1 2 , ' Ы u е ' : 20 , ' red ' : 5 }
def m i s s i n g ( ) :
non loc a l a d ded_c ount # З амыка н и е с сохр а н е н и ем с остоя н и я
add ed_count += 1
ret u rn 0
def m i s s i ng ( s e lf } :
s e lf . added += 1
ret u rn 0
def �c a l l� ( s e lf ) :
KJJaccw и васJJедовавие 93
self . added += 1
ret u r n 0
d ef read ( s e lf ) :
ret u r n open ( s elf . pat h ) . read ( )
d e f red u c e ( s e l f , ot h e r ) :
ra i s e Not im p l emented E r ro r
def red u c e ( s e l f , ot h e r ) :
s e lf . re s u lt += ot h e r . r e s u lt
»>
Имеетс я 4360 с трок
Классы и иаследоваиие 97
@c l a s smethod
def gen e rate_i n p ut s ( c l s , config ) :
ra i s e Not implement ed E r ro r
def read ( s e lf ) :
ret u rn open ( s e l f . path ) . read ( )
@c l a s smethod
def gen e rate_i n p ut s ( c l s , config ) :
98 Гяава З
def ma p ( s e lf ) :
r a i s e Not imp lemented E r ro r
def redu c e ( s e l f , ot h e r ) :
r a i s e Not implementedE rror
@c l a s smethod
def c reate_wo rke rs ( c l s , i n p ut_c l a s s , config ) :
wo r k e r s = [ ]
for in put_data in i n p ut_c l a s s . gene rate_i n p ut s ( c onfig ) :
wo r k e r s . a ppend ( c l s ( i n p ut_dat a ) )
ret u rn wor k e r s
c l a s s MyC h i l d C la s s ( My B a s eC l a s s ) :
def �i n it� ( s e l f ) :
MyBa s e C la s s . �i n it� ( s e l f , 5 )
>»
Результат первого вари а нта : ( 5 * 2 ) + 5 = 15
»>
Результат второ го в а р и анта такой же : 1 5
»>
Должно быть ( 5 * 5 } + 2 = 2 7 , фа ктичес к и : 7
foo = GoodWay ( 5 )
p r i n t ' Должно быть 5 * ( 5 + 2} 3 5 , фактичес к и : ' foo . va l u e
»>
Должно быть 5 * ( 5 + 2) = 3 5 , фактичес к и : 3 5
»>
[ < c l a s s · �m a i n� . GoodWay ' > ,
< c la s s · �m a i n� . Time s F iveCorrect ' > ,
< c la s s · �ma i n� . P l u sTwoCorrect ' > ,
ICJiaccы и иасJiедоваиие 103
c l a s s Imp l i c it ( My B a s eC l a s s ) :
d ef �init� ( s e l f , v a l u e ) :
s u p e r ( ) . �i n it� ( v a l u e * 2 }
a s s ert E x p l i c it ( 10 ) . va l u e = = Imp l i c it ( 10 ) . va l u e
>»
106 Глава З
>>>
{ ' l eft ' : { ' left ' : Non e ,
' pa rent ' : 10,
' r ight ' : { ' left ' : Non e ,
К.llассы в васпедовавве 107
my_t ree = NamedS u bTree ( ' fooba r ' , root . left . right )
print ( my_t ree . to_d i ct ( ) ) # Н и к а к и х бес конеч ных ци клов
»>
{ ' n ame ' : ' fooba r ' ,
' t ree_wit h_pa rent ' : { ' left ' : Non e ,
' pa rent ' : 7 ,
' right ' : Non e ,
' va l u e ' : 9 } }
c l a s s Ma c h i n e ( ToDictMi x i n , J s onMi x i n ) :
#
11 11 11
}
c l a s s MyObj ect ( ob j e ct ) :
def �init� ( self ) :
s e lf . puЫ ic_f i e l d = 5
self . �private_f i e l d = 10
»>
Att ribut e E r ro r : ' MyObj ect ' obj ect h a s n o att ri bute
� ' �p r i vate_field '
@c l a s smet hod
1 10 Глава 3
»>
Att r i b u t e E rror : ' MyC h i ldObj e c t ' o b j e c t h a s n o att r i b u t e
� ' _MyC h i ldObj e ct�p rivate_f i e l d '
»>
{ ' _MyPa rentOb j e ct�p rivate_f i e ld ' : 7 1 }
ICJiaccы в васJ1едовавве 111
d e f get_va l u e ( s e lf ) :
ret u rn st r ( s e l f . �v a l u e )
foo = MyC la s s ( S )
a s s e rt foo . get_va lu e ( ) == ' 5 '
c l a s s MyC l a s s ( MyBa s e C la s s ) :
# • • •
>»
Att r i b ut e E rror : ' My i n t egerSu b c l a s s ' o b j e c t h a s n o att ri bute
Ч:> ' _MyC l a s s_va l u e '
def get ( s e l f ) :
ret u rn s e lf . _v a l u e
c l a s s C h i ld ( Ap i C l a s s ) :
def _i n it_ ( s e lf ) :
s u p e r ( ) . _i n it_ ( )
self . _v a l u e = ' he l lo ' # Конфл и кт
а = C h i ld ( )
print ( a . get ( ) , ' и ' , a . _va l u e , ' должны различаться ' )
»>
hello и h e l l o должны р а зл и ч ат ь с я
def get ( se lf ) :
ret u rn self . _v a l u e
c l a s s C h i l d ( Ap i C la s s ) :
def _in it_ ( s e lf ) :
s u p e r ( ) . _i n it_( )
self . _v a l u e = ' he l lo ' # ОК !
1 14 Г.11ава З
а = C h i ld ( )
p r i nt ( a . get ( ) , ' и ' , a . _v a l u e , ' р азл и ч аютс я ' )
»>
5 и h e l lo разл и ч аютс я
s u p e r ( ) . �i n it�( membe rs )
def freq u e n cy ( s e l f ) :
counts = { }
for item i n s e l f :
c o u nt s . setdefa u lt ( it em , 0 )
c o u nt s [ it em ] += 1
ret u rn c o u n t s
»>
Дл и н а : 7
После рор : [ ' а ' , ' Ь ' , ' а ' , ' с ' , ' Ь ' , ' а ' ]
F requency : { ' а ' : З , ' с ' : 1 , ' Ь ' : 2 }
Как сделать так, чтобы этот класс вел себя как последовательность?
Python реализует варианты поведения контейнеров с помощью методов
экземпляров , имеющих специальные имена. Когда вы обращаетесь к
элементу последовательности по индексу:
bar = [ 1 , 2, З ]
ba r [ 0 ]
# Возвращает ( found , c o u nt )
d ef �getitem� ( s e l f , i n d ex ) :
fou n d , _ = s e lf . _s e a r c h ( 0 , i n d ex )
if n ot fou n d :
ra i s e I n d ex E r ro r ( ' Bыxoд и ндек с а з а пределы диапазона ' )
ret u rn fou n d . va l u e
len ( t ree )
»>
TypeE rror : object of type ' I n d e x a Ь l eNod e ' h a s п о l en ( )
»>
Де рево имеет 7 узлов
c l a s s BadType ( Se q u en c e ) :
pass
foo = BadType ( )
»>
TypeE rror : C a n ' t i n s t a n t i a t e a b st ract c l a s s Ba dType wit h
� abstract met hods �get it em� , �len�
»>
Инде кс 7 : З
С ч етч и к 10 : 1
def get_ohms ( s e l f ) :
120 Глава 4
ret u r n s e lf . _ohms
>>>
до : 50000 . 0
Посл е : 10000 . 0
s e l f . ohms = ohms
s e l f . voltage = 0
self . c u rrent = 0
@property
def voltage ( s e l f ) :
ret u r n self . _voltage
@voltage . s ette r
def voltage ( se lf , voltage ) :
s e lf . _voltage = voltage
s e lf . c u r rent = s e l f . _voltage / s e l f . ohms
»>
До : 0 А
После : 0 . 01 А
@property
def ohms ( s elf ) :
122 Глава 4
ret u rn s e lf . _ohms
@ohms . sett e r
d e f ohms ( s elf , ohms ) :
if ohms < = 0 :
ra i s e Va l u e E r ro r ( ' %f ohms должно быть > 0 ' % ohms )
self . _ohms = ohms
»>
»>
Va l u e E rror : - 5 . 000000 ohms должно быть > 0
@property
def ohms ( s e lf ) :
ret u rn s e lf . _ohms
@ohms . sett e r
def ohms ( s elf , ohms ) :
if h a s att r ( s e l f , ' _ohms ' ) :
ra i s e Att ribut e E r ror ( " Heвoзмoжнo установить атрибут " )
s e lf . _ohms = ohms
Метакпассы в атрибуты 123
»>
Att ribut e E rror : Невозможно уста новить атрибут
»>
до : 0
После : 0 . 1
мощью простых объектов Python . Здесь класс Buc ket представляет ос
тавшуюся квоту и длительность периода времени . в течение которого
квота будет доступна.
c l a s s B u c ket ( obj ect ) :
d ef _in it_ ( s e l f , period ) :
self . period_d e l t a = t imedelta ( s e c o n d s = p e r iod )
self . res et_t ime = d at et ime . now ( )
МетакJiассы и атрибуты 125
s e lf . q u ot a = 0
»>
Buc ket ( quot a = 100 )
»>
хватает дл я квоты 99
Buc ket ( q uot a = l )
126 Гпава 4
»>
Недостаточно дл я квоты З
B u c ket ( qu ot a = l )
d ef �repr� ( s e l f ) :
ret u r n ( ' B u c ket ( ma x_q uota =%d , q u ot a_c o n s umed =%d ) ' %
( s elf . max_q u ot a , s e lf . q uota_con s umed ) )
@q uota . sett e r
d e f quota ( s e l f , amount ) :
delta = self . ma x_q uota - amou пt
if amou пt = = 0 :
# Переустановка к воты н а новый период
self . q uot a_c o n s umed 0
self . ma x_q u ota = 0
e l if delta < 0 :
# З а п ол н е н и е квоты н а н овый п е р и од
a s s e rt self . q u ot a_c o п s umed = = 0
s e l f . ma x_q uota = amouпt
else :
# Потребл е н и е квоты з а п е р и од
a s s e rt s e l f . max_q u ot a >= self . q uota_c o n s umed
self . q uota_c oп s umed += d e l t a
if deduct ( b uc ket , З ) :
p r iпt ( ' Хватает для квоты З ' )
else :
рriпt ( ' Недостаточ но дл я квоты З ' )
>»
I п it i a l B u c ket ( ma x_q uot a = 0 , q u ota_c o п s umed = 0 )
F i lled Buc ket ( max_q uot a = 100 , q u ot a_c o п s umed = 0 )
Хватает для квоты 9 9
Сейчас Buc ket ( max_quot a = 100, q u ot a_c o п s umed=99 )
Недостаточн о для квоты З
Все еще имеет ся B u c ket ( ma x_q uot a = 100 , q uota_c on s umed=99 )
128 ГJiава 4
@g rade . s ett e r
d e f grad e ( s e l f , v a l ue ) :
if n ot ( 0 < = v a l u e < = 100 ) :
ra i s e Va l u e E rror ( ' З нa ч e н и e оце н к и должно н аходиться
� в предел а х от 0 до 100 ' )
self . _grade = v a l u e
@stati cmet h od
def _c h e c k_grade ( va l u e ) :
if n ot ( 0 < = v a l u e < = 100 ) :
ra i s e Va l u e E r ro r ( ' З н a ч e н и e оце н к и должно н аходиться
� в предел а х от 0 до 100 ' )
@prop e rty
d ef w r it in g_grade ( s e l f ) :
ret u rn s e l f . _writ i n g_grade
@prope rty
d ef math_grade ( s e l f ) :
ret u rn s e l f . _math_grade
c l a s s Exam ( ob j e c t ) :
# Атри буты кла с с а
math_grade = Grade ( )
writ ing_grade = Grade ( )
s c ie n c e_grade = Grade ( )
d e f �set� ( s e l f , i n s t a n c e , va l u e ) :
if n ot ( 0 < = va l u e < = 100 ) :
ra i s e Va l u e E r ro r ( ' З н a ч e н и e оце н к и должно н а ходит ь с я
� в пределах о т 0 д о 100 ' }
self . _v a l u e = v a l u e
132 Глава 4
»>
л итературоведе н и е 82
Наука 99
>»
Второй 7 5 п равильно
Первый 7 5 неправильно
Суть проблемы заключается в том , что для атрибута класса wri t i ng_
grade один экземпляр Grade разделяется всеми экземплярами Exam. Эк
земпляр Grade для этого атрибута конструируется только один раз за
все время жизни программы при первоначальном определении класса
Exam. а не всякий раз . когда создается экземпляр Exam.
Чтобы решить эту проблему, нужно , чтобы класс Grade отслеживал
свои значения для каждого отдельного экземпляра Exam. Мы можем это
обеспечить, сохраняя состояние каждого экземпляра в словаре.
c l a s s Grad e ( ob j e ct ) :
def �in it� ( s e lf ) :
self . _va l u e s = { }
def �set� ( s e lf , i n s t a n c e , v a l u e ) :
if n ot ( 0 < = v a l u e < = 100 ) :
ra i s e Va l u e E rro r ( ' З н a ч e н и e оце н к и должно н аходить с я
Метак лассы и атрибуты 133
first_exam = Exam ( )
f i r st_exam . wr it i ng_grade = 82
second_exam = Exam ( )
second_exam . writ i ng_grade = 7 5
рrint { ' Первый ' , f i rst_exam . wr i t i ng_gra d e , ' пра вильно ' )
print { ' Bтopoй ' , s e c ond_exam . wr i t i ng_grad e , ' п равильно ' )
>»
Первый 82 правильно
Второй 75 правильно
134 ГJ1ава 4
g e t a tt r ib u t e ( ) и se t a tt r ( )
_ _ _ _
data = La zyDB ( )
print ( ' до : ' , data . _d ict_)
print ( ' foo : ' , data . foo )
print ( ' Пocлe : · , d a t a . _d i ct_)
>»
до : { ' e x i st s ' : 5 }
foo : З н а ч е н и е для foo
После : { ' e x i s t s ' : 5 , ' foo ' : ' З н а ч е н и е для foo ' }
»>
ex i st s : 5
Вызов _get a t t r_ ( foo )
foo : З н а ч е н и е для foo
foo : З н а ч е н и е для foo
»>
Вызов _getattribute_ ( e x i st s )
e x i st s : 5
Вызов _getat t ribute_ ( foo )
foo : З н а ч е н и е для foo
Вызов _get att ribute_ ( foo )
foo : З н а ч е н и е для foo
c la s s Mi s s ingPrope rtyDB ( ob j e ct ) :
def _get att r_ ( s e l f , name ) :
if name == ' ba d_n ame ' :
ra i s e Att r i b ut e E r ro r { ' Oтcyтcтвyeт %s ' % name )
# ...
data = M i s s i ngPropertyDB { )
data . ba d_n ame
>»
Att ribut e E rror : Отсутс твует b ad_n ame
>»
до : { ' e x i s t s ' : 5 }
Вызов _get att r_ ( foo )
foo сущес твует : True
После : { ' e x i st s ' : 5 , ' foo ' : ' З н а ч е н и е дл я foo ' }
foo существует : True
>»
Cal led _get att r i b ute_ ( foo )
foo существует : True
Вызов _getatt ribute_ ( foo )
foo существует : True
s u pe r ( ) . _s etatt r_ ( n ame , va l u e )
атрибута.
c la s s LoggingSavi ngDB ( S avingDB ) :
def _setatt r_ ( s e l f , n a m e , v a l u e ) :
р r i пt ( ' Вызов _setatt r_ ( %s , % r ) ' % ( n ame , v a l u e ) )
s u pe r ( ) . _s et att r_ ( n ame , va l u e )
d a t a = LoggingSavingDB ( )
p rint ( ' до : ' , data . _d i ct_ )
d a t a . foo = 5
p r int ( ' После : ' , data . _d i ct_ )
data . foo = 7
р r i пt ( ' Окончательно : ' , data . _d i c t_ )
»>
до : { }
Вызов _setatt r_ ( foo, 5 )
После : { ' foo ' : 5 }
Вызов _setatt r_ ( foo , 7 )
Окончательно : { ' foo ' : 7 }
»>
Вызов _getatt ribute_ ( fo o )
Вызов _get att r i bute_ ( _d at a )
Вызов _get att ri bute_ ( _d at a )
Traceba c k . . .
Runtime E rror : maximum rec u r s ion d e p t h exceeded
d ef foo ( s e lf ) :
pass
c l a s s MyC l a s s i п Pythoп 2 ( ob j e c t ) :
_met a c l a s s_ = Met a
# ...
@c l a s smet hod
def iпter ior_a п g l e s ( c l s ) :
ret u rп ( c l s . s i d e s - 2 ) * 180
c l a s s Triaпgl e ( Polygoп ) :
sides = 3
142 Гпава 4
»>
До c l a s s
д о s id e s
После s id e s
Traceback . . .
Va l u e E r ro r : Многоу г ол ь н и к должен иметь н е менее з с торон
c l a s s Seria l i z a Ы e ( obj e c t ) :
def �init� ( s e l f , * a rgs ) :
s e lf . a rgs = a rgs
def s e r ia l i z e ( s e lf ) :
ret u r n j s on . d u m p s ( { ' a rgs ' : s e lf . a rgs } )
point = Point 2D ( S , 3 )
print ( ' Объект : ' , point )
рriпt ( ' Сериализованный объект : ' , point . s e r i a l i z e ( ) )
>»
Объе кт : Po i n t 2D ( S , 3 )
Сериал изованный объект : { " a rgs " : ( 5 , 3 ] }
»>
До : Bette rPoint2D ( S , З )
С е р и ал и зованный объект : { " a rg s " : [ 5 , З ] }
Посл е : Bett erPoint 2D ( S , З )
def s e r i a l i z e ( s e lf ) :
ret u r n j s on . dumps ( {
' c l a s s ' : s e l f . �c la s s� · �name�,
' a rgs ' : s e lf . a rgs ,
})
def �rep r� ( s e l f ) :
# • • •
>»
После : EvenBett e rPo i n t 2D ( S , 3 )
Сериал изов а н ны й объект : { " c la s s " : " EvenBetterPoint2D " ,
" a rgs " : [ 5 , 3 ] }
После : Even Bette rPoint 2 D ( S , 3 )
»>
Key E r ror : ' Point3D '
c la s s Registered S e ri a l i z a Ы e ( Bett e rS e r i a l i z a Ы e ,
met a c l a s s =Met a ) :
pass
v 3 = Vector3D ( 10 , - 7 , 3 )
p r i nt ( ' До : ' , v3 )
data = v3 . s e r i a l iz e ( )
р r i nt ( ' С е р и а л и зованный объект : ' , data )
p r i nt ( ' Пocл e : ' , d e s e r i a l i z e ( data ) )
»>
до : Vector3D ( 10 , - 7 , 3 )
С е р и ал и зованный объект : { " c l a s s " : " Vector3D " , " a rgs " : [ 10 , - 7 , 3 ] }
Посл е : Vector3D ( 10 , - 7 , 3 )
def _set_ ( s e l f , i n s t a n c e , va l u e ) :
setatt r ( i n st a n c e , s e l f . i n t e r n a l_n ame , va l u e )
»>
до : . { }
•
c l a s s F i eld ( object ) :
def _init_( s e l f ) :
# Эти з н а ч е н и я будут п р и с воены мета кл а с с ом
s e lf . name = None
s e lf . i nt e r n a l_name = None
#
»>
до : {}
После : ' E u l e r ' { ' _f i r st_n ame ' : ' E u l e r ' }
150 Г.яава 4
»>
H e l l o from t h e c h ild !
>»
Выпол н е н и е . . .
Выпол н е н и е . . .
Код выхода 0
st a rt = t ime ( )
proc s = [ ]
for _ i n range ( 10 ) :
p roc = ru n_s leep ( 0 . 1 )
p roc s . append ( p roc )
Далее можно использовать метод commu n i c ate ( ) для того, чтобы до
ждаться завершения операций ввода-вывода процессов и прекращения
их выполнения .
»>
За верше но з а 0 . 117 с е кунд
Примечание
Если бы эти п роцессы выпол нялись последовательно, то общее в ремя задержки со
ставило бы 1 секунду, а не -0, 1 секунды .
Вы также можете отправлять данные из своей программы на Python
в подпроцесс и получать его вывод. Это позволяет использовать другие
программы для паралл ельной работы. Предположим, например , что вы
хотите использовать средство командной строки open s s l для шифрова-
154 ГJJава 5
»>
b ' o4, G \ x 9 1 \ x 9 5 \ xfe\xa0\xa a \ xЫ '
Ь ' \х0Ь \ х01 \ \ \х Ы \ хЫ \ хf Ь \ х ЫС \ хеlЬ '
b ' d s \ x c 5 \xf4 ; j \ xlf\xd0c - '
stdout = s u b p roc e s s . P I P E )
ret u rn p roc
Примечание
Встроенн ы й модул ь Python h a s h l i b предоставляет фун кцию md 5 ( ) , поэтому вы
полнение подпроцесса, как показано вы ше, не всегда необходимо. Цел ью а втора
было лишь продемонстрировать, как подпроцессы могут перена п ра влять входные
и выходные потоки.
Далее мы можем запустить группу процессов open s s l для шифрова
ния определенных данных и другой набор процессов для хеширования
данных, зашифрованных с помощью функции md5 ( ) .
input_p roc s = [ ]
h a s h_pro c s = [ ]
for i n range ( З ) :
data = os . u ra n d om ( 10 )
proc = run_open s s l ( data )
i n put_p roc s . a p p e n d ( p roc )
h a s h_proc = ru n_md S ( p roc . stdout )
h a s h_proc s . a p p e n d ( h a s h_proc )
»>
b ' 7a182287Sdcf9650a 5 a 7 1 e 5 e41e77bf3 '
b ' d41d8 c d98f00Ы04e9800998ecf8427e '
b ' 1 720f581 cfdc448b6273048d426 2 1 100 '
»>
За няло 1 . 040 с е кунд
d ef ru n ( s e lf ) :
s elf . fa ctors = l i st ( f a c t o r i z e ( s e l f . numbe r ) )
»>
З а н яло 1 . 06 1 с е кунд
»>
За няло 0 . 503 с е кунд
160 Г.яава 5
for i i n range ( S ) :
c ompute_h e l i c opte r_loc at ion ( i )
for t h read i n t h re ad s :
t h read . j o i n ( )
end = t ime ( )
р r i nt ( ' З а няло % . Зf с е кунд ' % ( en d - st a rt ) )
»>
З а няло 0 . 102 с е кунд
нием системных вызовов и заново захватывают GIL. как только эти вы
зовы будут выполнены .
Кроме потоков , су�цествует много других способов дл я работы с бло
кирующим вводом-выводом, например встроенный модуль a sync io, и
эти альтернативные способы обладают важными преиму�цествами. Од
нако данные варианты требуют проведения дополнительной работы
по рефакторингу кода с целью адаптации к другой модели выполнения
(раздел "Рекомендация 40. Используйте сопрограммы для одновремен
ного выполнения нескольких функций") . Использование потоков - это
простейший способ блокирования операций ввода-вывода, требующий
внесения минимальных изменений в вашу программу.
c o u n te r . i n c rement ( l )
»>
Ожидаемое з н а ч е н и е с ч етч и ка : 500000 , фа ктичес кое : 278328
re s u lt_a = v a l u e_a + 1
s etatt r ( c o u n t e r , ' count ' , r e s u lt_a )
it em = s e l f . i п_q u e u e . get ( )
e x c e pt I п d ex E r ror :
s l ee p ( 0 . 01 ) # Отсутствие да нных для обработки
else :
re s u lt = s e l f . fu п c ( it e m )
s e lf . out_q u eu e . put ( re s u lt )
s e lf . wor k_d o п e += 1
Теперь можно объединить все три фазы путем создания очередей для
точек их координации и соответствующих рабочих потоков.
dowпload_q u e u e = MyQueue ( )
re s i z e_q u e u e = MyQu e u e ( )
upload_queue = MyQu eu e ( )
doпe_queue = MyQue ue ( )
t h reads = [
Worke r ( dowп loa d , d owп load_q u e u e , res i z e_q u e u e ) ,
Worke r ( re s i z e , r e s i z e_q u e u e , u p load_q u eu e ) ,
Worke r ( u p load , u p load_q u e u e , doпe_q u eu e ) ,
»>
Обра бота но 1000 элементов после 3030 опросов
def c o n s ume r ( ) :
р r i nt ( ' Потребител ь ожидает дан ные ' )
Одвовремеввость и паралnеJIИзм 169
»>
Потребител ь ожидает дан ные
Производител ь поставл я ет дан ные
Потребител ь за вершил обработку данных
Производитель завершил поста в ку дан ных
мере однажды. прежде чем второй вызов метода put ( ) прекратит блоки
ровку и добавит второй элемент в очередь.
q u e u e . put ( ob j e c t ( ) ) # Выпол няется первым
р r i пt ( ' Произ водитель поставил дан ные 1 ' )
q u e u e . put ( ob j e ct ( ) ) # Выпол н я ет с я третим
р r i пt ( ' Произ водитель поста в ил дан ные 2 ' )
t h read . j o i п ( )
р r i пt ( ' Произ водитель з а в ерш ил поставку да нных ' )
»>
Произ водител ь поставил дан ные 1
Потребитель за верш ил получ е н и е да н ных 1
Произ водител ь поставил дан ные 2
Потреб ител ь за вершил получ е н и е данных 2
Произ водител ь за вершил поставку данных
d ef c o п s ume r ( ) :
р r i пt ( ' Потребитель ожидает получен и я да нных ' )
work = i п_q u e u e . get ( ) # Выпол няется вторым
р r i пt ( ' Потребитель обра батывает данные ' )
# Выпол н е н и е работы
# • • •
»>
Потребител ь ожида ет получе н и я данных
Произ водитель выжидает поставлять дан ные
Потребител ь обра батывает дан ные
Потребител ь за вершил обработку да н ных
Произ водител ь завершил поста в ку да н ных
def c lose ( s e lf ) :
s e lf . put ( s e lf . S E NTI N E L )
def run ( s e lf ) :
for it em i n s e l f . in_q u e u e :
172 Гпава 5
re s u lt = s e lf . fu n c ( item )
s e l f . out_q u e u e . put ( re s u lt )
t h re a d s = [
Stop p a Ь l eWo r ke r ( down loa d , down load_q u e u e , r e s i z e_q u e u e ) ,
# • . •
>»
1000 элементов обработано
it = my_c o rout i ne ( )
next ( it ) # Подготов ить с о п р о г р амму
it . s e nd ( ' Пepвый ' )
it . s e nd ( ' Bтopoй ' )
»>
Полу ч е н о : Первый
Получ ено : Второй
print ( it . se nd ( - 1 ) )
»>
10
4
4
-1
t ry :
it . seпd ( EMPТY ) # Передать с остоя н и е q 8 , получить couпt
exc ept Stopite ratioп a s е :
рriпt ( ' Счетч и к : ' , e . va l u e ) # З н а ч е н и е , возвраще нное ret u rп
»>
Первый резул ьтат : Query ( y=ll , x = S )
второй результат : Qu e ry ( y=ll , х=б )
Счетч и к : 2
def step_c el l ( y , х ) :
state = y i e l d Q u e ry ( y , х )
пeighbors = y i e l d f rom c o u пt_п eigh bors ( y , х )
178 Гяава Б
it = step_c e l l ( 10 , 5 )
q 0 = next ( it ) # Начальный объект q u e ry
p r i nt ( ' Я : ' , q 0 )
q l = it . s e n d ( A L IVE ) # Пе редать с вое с о с тоян и е ,
# получить состоя н и е с о с еда
p r i nt ( ' Ql : ' , q l )
# • • •
»>
Ме : Query ( y = 10 , x= S )
Ql : Query ( y=ll , x= S )
def �st r� ( s e l f ) :
# • • •
p r i nt ( g rid )
>»
- - -
* - - - - -
- - - - * - - - -
- -
*** - - - -
c l a s s Column P rinte r ( o b j e c t ) :
# ".
print ( c o lumn s )
»>
0 1 2 з 4
- - -*- - - - -
----*---- - -*-*- - - - ----*---- - - -*-- -- - ----*----
- - *** - - - - - - -**- - - - --*-*---- - - - - ** - - - -----*---
---*----- - - -**- - - - - - -**- - - - - - -***- - -
Сопрограмм ы в Python 2
К сожалению , в Python 2 отсутствуют некоторые синтаксиче
ские изюминки , которые делают сопрограммы столь элегантными в
Python 3. Речь идет о двух ограничениях. Во-первых, отсутствует выра
жение yield from. Это означает, что если вы хотите скомпоновать вме
сте сопрограммы-генераторы в Python 2, то вам потребуется включить
дополнительный цикл в точке делегирования полномочий .
# Pyt hon 2
def d e l egated ( ) :
yield 1
yield 2
def compo s ed ( ) :
yield ' А '
for v a l u e i n d e l egat ed ( ) : # y i e l d from в Pyt hon З
yield va l u e
yield В ' '
182 ГJ1ава 5
p r i n t l i st ( c omposed ( ) )
»>
[ ' А ' , 1, 2, ' В ' )
def de legated ( ) :
yield 1
ra i s e MyRet u rn ( 2 ) # ret u r n 2 в Pyt hon 3
y i e l d ' Не дост и г нуто '
def c ompo s ed ( ) :
t ry :
for v a l u e i n d e l egated ( ) :
yield value
exc e pt MyRet u rn a s е :
output = e . va l u e
y i e l d output * 4
p r i n t l i st ( c omposed ( ) )
»>
[1, 8)
>»
З а няло 1 . 1 70 с е кунд
Одвовремеввость и пара.JШе.1111а м 185
»>
Заняло 1 . 199 с е кунд
»>
Заняло 0 . 66З с е кунд
»>
fibon a c c i ( ( 1 , ), {}) -> 1
fibona c c i ( ( 0 , ), {}) -> 0
fibona c c i ( ( l , ), {}) -> 1
f i bon a c c i ( ( 2 , ), {}) -> 1
fibon a c c i ( ( З , ), {}) -> 2
во внешнюю функцию.
d e f t r a c e ( fu n c ) :
@wrap s ( fu n c )
def wra pper ( * a rg s , * * kwa rgs ) :
# . • •
ret u r n wrapper
@t race
def f i bona c c i ( n ) :
# ...
fibonac c i ( n )
Воз вратить n - e ч и сло Фибо н а ч ч и
my_fu n c t i on ( )
»>
В блоке :
Отл адоч ные да нные
Сообще н и е об о ш ибке
Допол н ительные отладоч ные да н н ые
Посл е блока :
E rror log h e re
t ry :
y i e l d logge r
fina lly :
logge r . s et L eve l ( o ld_leve l )
>»
Это мое сообще н и е !
»>
Сообщения об оши б к а х будут выводиться
П римечание
Формат сериал изации, используемый модулем pickle, изначально небезопасен.
Сериал изова н н ые дан н ые по существу представля ют собой п рограмму, описы ваю
щую способ реконструи рования исходного объекта Python. Это означает, что вре
доносная полезная нагрузка может быть испол ьзована с цел ью создан ия угроз для
любой части программы на Pythoп, которая пытается десериализовать да нные.
В п ротивоположность этому модул ь j sоп спроекти рова н ка к безопасный. Сериали
зова н н ые JSОN-да нные содержат простое описание иерархии объектов. Десериа
лизованные данные не подвергают программы на Python н и ка ким дополн ительным
рискам. Дл я обмена да нными между п рограммами или л юдьми, не пользующимися
взаимными доверител ьными отношениями, должны использоваться та кие форма
ты, как JSON.
Предположим, например, что вы хотите использовать объект Python
для того, чтобы представлять прогресс игрока. Состояние игры включает
уровень, на котором находится игрок, и количество оставшихся жизней.
c la s s GameSt at e ( object ) :
def � i n it� ( s e lf ) :
s e lf . level = 0
s e lf . l ives = 4
»>
{ ' l ives ' : З , ' leve l ' : 1 }
Все бьmо б ы хорошо , н о есть одна проблема. Как быть в том случае ,
когда возможности игры со временем расширятся. Предположим , вы
решили , что игрок может зарабатывать очки , стремясь добиться мак
симально высокого счета в игре. Дтlя подсчета очков, зарабатываемых
игроком , в класс GameState необходимо ввести новое поле .
c l a s s Gamest at e ( obj ect ) :
d ef �in it� ( s e l f ) :
# • • •
self . point s = 0
Сериализация новой версии класса GameState с помощью модуля
pickle будет работать точно так же , как и до этого. Ниже мы имитируем
круговой процесс сохранения и восстановления состояния игры через
файл путем сериализации строки с помощью метода dump ( ) и обратного
преобразования строки в объект с помощью метода load ( ) .
state = GameStat e ( )
seria l i zed = p i c k l e . dump s ( state )
state_aft e r = p i c k l e . loa d s ( se r i a l i z ed )
print ( state_aft e r . �d i ct�>
»>
{ ' lives ' : 4 , ' level ' : 0 , ' po i nt s ' : 0 }
Но что произойдет с сохраненными гораздо ранее старыми объекта
ми GameState, которые пользователь также может захотеть восстано
вить? Ниже мы восстановим файл старой игры. используя программу с
новым определением класса GameState.
with open ( state_p at h , ' rb ' ) a s f :
state_aft e r = p i c k l e . load ( f )
print ( state_aft e r . �d i ct�>
>»
{ ' l ives ' : 3 , ' level ' : 1 }
198 Гпава 6
>»
{ ' l ives ' : 4 , ' level ' : 0 , ' po i nt s ' : 1000 }
>»
{ ' leve l ' : 0 , ' po i n t s ' : 1000 , ' ma g i c ' : 5 , ' l ive s ' : 4 }
Управление версиям и
Иногда в объекты Python приходится вносить изменения . удаляя не
которые поля в интересах обратной совместимости. В этом случае под
ход. основанный на использовании аргументов, заданных по умолча
нию , перестает работать.
200 Гпава 6
>»
Type E rror : �in it�< > got a n u n e xpected keyword a rgument ' l ives '
»>
{ ' ma g i c ' : 5 , ' l evel ' : 0 , ' po i n t s ' : 1000 }
»>
Att ribut e E rror : C a n ' t get att r i b u t e ' GameSt at e ' o n < mod u l e
� ' _ma in_ ' f rom ' my_c ode . py ' >
»>
b ' \x80\x0Зc_m a i n_\nGameSt a t e \ n q \ x00 ) '
»>
b ' \ x80\x03 c_ma i n_\ n u n p i c k l e_game_st a t e \ n q \x00 } '
Модуль time
Функция loc a l t i me ( ) из встроенного модуля t ime позволяет преоб
разовывать временные метки UNIX (количество секунд в UТС , истекших
с момента настуrтения эры UNIX) в локальное время. соответствующее
часовому поясу хоста (в моем случае - тихоокеанскому летнему време
ни, РDТ) .
from t ime import l o c a lt im e , st rft ime
now = 14076947 10
loc al_t u p l e = loca ltime ( now )
t ime_format = ' %Y - %m - %d %Н : %М : %5 '
t ime_st r = st rft ime ( t ime_fo rmat , loc a l_t u p l e )
print ( t ime_st r )
»>
2014 - 08 - 10 1 1 : 18 : 30
>»
2014-05 -01 1 5 : 45 : 16
204 ГJiава 6
»>
Va l u e E rror : u n c o n v e rted data remai n s : EDT
Модуль datetime
В Python имеется возможность представлять время также с помощью
класса datet ime из встроенного модуля datetime. Модуль d atetime. как
и модуль t ime , можно использовать для перехода от текущего времени.
выраженного в системе UТС . к местному времени.
Ниже время в системе UТС преобразовано в заданное на компьютере
автора тихоокеанское поясное время .
f rom datetime import datet ime , t imezone
»>
2014 - 08 - 10 1 1 : 18 : 30 - 07 : 00
>»
1407694710 . 0
»>
2014 - 05 - 02 03 : 3 3 : 24+00 : 00
»>
2014 - 0 5 - 01 20 : 3 3 : 24 - 07 : 00
206 Гяава 6
»>
2014 - 05 - 02 09 : 18 : 24+05 : 45
Двухсторонняя очередь
Класс dequeue из модуля col lection s - это двухсторонняя (двусвяз
ная) очередь. Он обеспечивает возможность добавления и удаления
элементов как в начало, так и в конец очереди , причем эти операции
выполняются по алгоритму с классом временной сложности постоян
ного времени. Благодаря этому данный класс является идеальным для
очередей с дисциплиной обслуживания FIFO (сокращ. от "First In. First
Out" - "первым пришел - первым обслужен") .
fifo = deque ( )
fifo . append ( l ) # Производитель
х = fifo . popleft ( ) # Потребител ь
p r i nt ( a )
p rint ( b )
р r i пt ( ' Ра в н ы ? ' , а - - Ь )
»>
{ ' foo ' : 1 , ' ba r ' : 2 }
{ ' ba r ' : 2 , ' foo ' : 1 }
Равны ? True
for v a l u e l , v a l u e 2 in z i p ( a . v a l u e s ( ) , b . v a l u es ( ) ) :
p rint ( va l u e l , v a l u e 2 )
»>
1 red
2 Ыuе
Словарь по умолчани ю
Словари удобны для учета данных и отслеживания статистики. Од
ной из трудностей работы со словарями является то, что вы не можете
заранее предполагать наличие какого-либо ключа. Из-за этого даже та
кие простые операции. как инкрементирование счетчика. хранящегося
в словаре, становятся громоздкими.
stat s = { }
key = ' my_c ount e r '
if key not in stat s :
stat s [ key ] = 0
stat s [ k ey ] += 1
»>
До : [ З , 4 , 7 , 5 ]
Посл е : [ З , 4 , 5 , 7 ]
210 Гпава 6
Двоич ны й поиск
Длительность поиска элемента линейно растет с увеличением длины
списка. если вызывать метод i n dex ( ) .
х = l i st ( range ( 10 * * 6 ) )
i = x . i nd ex ( 99 1 2 3 4 )
Итератор ы
Встроенный модуль itertoo l s содержит большое количество функ
ций . предназначенных для работы с итераторами (более подробно см .
в разделах "Рекомендация 1 6. Не упускайте возможность использовать
генераторы вместо возврата списков" и "Рекомендация 1 7 . Не забывай
те о мерах предосторожности при итерировании аргументов") . Не все
они доступны в Python 2 . но их можно легко встроить. действуя соглас
но простым способам . документированным в модуле. Справку об этом
вы сможете получить, выполнив в командной строке интерактивного
сеанса работы с Python команду h e l p ( itertool s ) .
Функции i tertoo l s можно разделить на три основные категории.
+ Связывание итераторов .
• c h a i n ( ) . Объединяет несколько итераторов в один последова
тельный итератор.
• cyc le ( ) . Бесконечно повторяет элементы итератора.
• tee ( ) . Разбивает итератор на несколько параллельных итера
торов .
Встроенные модуJIИ 211
>»
5 . 364999999999999
>»
5 . 36
»>
0 . 004166666666666667
»>
0.0
»>
5 . 365
»>
5 . 37
»>
0 . 004166666666666666666666666667
>»
0 . 01
S u c c e s s fu l ly i n s t a l led pyt z
Cleaning up . . .
»>
Возвраща ет T r u e , е с л и зада н ное слово я вляется п а л и ндромом . '
вопроса вы найдете на сайте РЕР 257 (http : / /www . pyt hon . o rg/ dev / pe p s /
рер - 0257 /). Также существуют стандарты оформления строк докумен
тирования. которые вы должны обязательно соблюдать.
Документирование модулей
Каждый модуль должен снабжаться строками документирования
верхнего уровня. Этот строковый литерал должен быть первой инструк
цией в файле исходного кода, а также начинаться и заканчиваться тре
мя двойными кавычками ( " " " ) . В него помещают сведения о модуле и
его содержимом ознакомительного характера.
Первая строка документирования должна содержать единственное
предложение, описывающее назначение модуля . В следующих абзацах
должно содержаться подробное описание работы модуля, рассчитанное
на пользователей . Строки документирования модуля служат отправ
ным пунктом , в котором можно отдельно выделить важные классы и
функции , принадлежащие модулю.
Ниже приведен пример строки документирования модуля .
# word s . py
# ! / u s r/ b i п / eпv руt h о п З
" " " Библ и отека для тестиров а н и я с л о в с помощью р а зл и ч ных
л и н г ви с т и ч е с к и х шаблонов .
Документирование классов
Каждый класс должен снабжаться строками документирования уров
ня класса. В основном эти строки следуют тому же шаблону. что и стро
ки документирования уровня модуля . Первая строка должна состоять
220 Глава 7
# • • .
Документирование функqи й
Каждая общедоступная функция и метод должны снабжаться стро
ками документирования. Эти строки должны следовать тому же ша
блону, что и модули и классы. Первая строка должна состоять из одно
го предложения и содержать описание функции. Последующие абзацы
должны содержать описание специфического поведения и аргументов
функции. Также должны быть указаны возвращаемые значения и опи
саны исключения, которые вызывающий код должен обрабатывать как
часть интерфейса функции .
Ниже приведен пример строки документирования функции.
d ef fi nd_a nagrams ( word , d ic t iona ry ) :
'"' " На ходит в с е а н а г р аммы для слова .
Ар гументы :
word : строка целевого слова .
d i ct ioп a ry : конте й н е р , с одержащи й в с е с тро к и , о которых
известно, что они п редс та вляют с обой дей с твител ьные слова .
возвращаемые з н а ч е н и я :
Список н а йде н ных а н а г рамм . Е сл и н и одно слово не н а йдено,
Э Т О Т С П И С О К пусто й .
П римечание
После того как вы зап ишете строки документи рован и я для своих модулей, важно
следить за обновлением документации. Встроен н ы й модуль d o c t e s t упрощает
выполнение контрол ьных п римеров, вкл ючаемых в строки документирования для
того, чтобы можно было убедиться в том, что между исходным кодом и документа
цией со временем не возника ют расхожден ия.
Примечание
В Pythoп 3.4 введен более гибкий способ определения па кетов: п ространства имен.
Пространства имен могут вкл ючать модул и из совершенно разных каталогов, zi р
архивов и даже удаленных систем. За более подробными сведениями о п ростран
ствах имен обратитесь к документу РЕР 420 (http : / /www . pyt hon . org/dev/ p e p s /
рер - 0420/).
Предоставляемая пакетами функциональность преследует в про
граммах на языке Python две основные цели , которые описаны ниже.
Пространства имен
Прежде всего , пакеты предназначены для того , чтобы облегчить
группирование модулей по различным пространствам имен . Это по
зволяет иметь много модулей с одним и тем же именем , но различны
ми путями доступа. которые являются уникальными. Например . ниже
приведен фрагмент программы, которая импортирует атрибуты из двух
модулей с одним и тем же именем ut i l s . ру. Это возможно, поскольку к
модулям можно обращаться , используя их абсолютные пути.
# ma in . py
from a n a lys i s . ut i l s import log_ba s e 2_b u c ket
from f rontend . ut i l s import s t r i ngify
va l u e = З З
if a n a lys i s_i n s pe c t ( va l u e ) = = frontend_i n s pect ( va l ue ) :
р r i n t ( Р а венс т во ! )
' '
П римечание
Другой подход, позволя ющий избежать конфл и кта между импортирова н н ы ми име
нами, заключается в том, чтобы п ри обращении к именам всегда использовать уни
кал ьное имя модуля с наивысшим положен ием в иера рхи и.
П рименител ьно к приведен ному выше примеру вы п режде всего должны импор
ти ровать модул и a n a ly s i s . u t i l s и frontend . ut i l s с помощью и н струкц ий
import. После этого вы должн ы обра щаться к фун кциям i n s p e c t ( ) , используя
пол н ы е пути доступа к н и м : a n a ly s i s . ut i l s . i n s pect ( ) и frontend . u t i l s .
i n s pect ( ) .
Такой подход изба вляет от необходимости испол ьзовать предложен ие a s . Он та к
же делает для новых читателей совершен но очевидным то, где именно оп ределена
каждая функция.
Сmабил ьн ые АРI
Второе назначение пакетов в Python это предоставление строго
-
а = P roj e c t i le ( l . S , 3 )
Ь = P roj e c t i le ( 4 , 1 . 7 )
aft e r_a , aft e r_b = s im u late_c ol l i s io n ( a , Ь )
t ry :
we ight = my_mod u l e . d e t e rm i п e_we ight ( l , - 1 )
e x c e pt my_mod u l e . I п v a l idDe п s ity E r ro r :
weight = 0
e x c e pt my_mod u l e . E r ro r a s е :
logg iпg . e rror ( ' OШибкa в вызывающем коде : %s ' , е )
exc e pt E x c eptioп a s е :
logg i п g . e r ro r ( ' Owибкa в коде АР! : %s ' , е )
ra i s e
c l a s s Volume E r ror ( E r ro r ) :
" " " Базовый кл а с с для о ш ибок п р и ра с чете объема . " " "
def s h ow ( ) :
# • • •
Проблема в том, что мо.цуль а рр, который содержит объект prefs , им
портирует также класс d i a l og, необходимый для отображения диалого
вого окна при запуске программы.
# а р р . ру
import d i a log
c l a s s Pref s ( ob j e c t ) :
# • • •
prefs = P refs ( )
d i a log . s how ( )
# а рр . ру
c l a s s Prefs ( ob j e c t ) :
#
prefs = Prefs ( )
c l a s s D i a l og ( obj ect ) :
# . • •
save_d i a log D i a l og ( )
def show ( ) :
# • . .
def configu re ( ) :
s ave_d i a log . s ave_d i r = a p p . p refs . get ( ' save_d i r ' )
p refs = Prefs ( )
def c onfigu re ( ) :
# . . •
app . c onfigu re ( )
d i a log . configure ( )
d i a log . s h ow ( )
s ave_d ia log = D i a l og ( )
d ef s h ow ( ) :
import а р р # Dyn a m i c import
s ave_d i a l og . s ave_d i r = a p p . p refs . get ( ' save_d i r ' )
# • • •
c l a s s P refs ( ob j e c t ) :
#
p refs = P refs ( )
d ia log . s how ( )
что все другие модули уже инициализированы (шаг 5 уже завершен для
всех модулей) .
В целом лучше избегать динамического импорта. Накладными рас
ходами операций импорта нельзя пренебрегать, особенно в случае ин
тенсивных циклов . Кроме того, откладывая выполнение, динамический
импорт может преподнести вам сюрпризы на этапе выполнения, такие
как исключения Syntax E r ror, возникающие спустя длительное время
после запуска программы (о том , как избежать подобных ситуаций, см .
в разделе "Рекомендация 56. Тестируйте любой код с помощью модуля
un ittest"). Однако даже с учетом указанных недостатков данный спо
соб часто оказывается лучше альтернативы в виде реструктуризации
всей программы .
Name : S p h i n x
Ve r s ion : 1 . 2 . 2
Location : / u s r/ lo c a l / l ib/ pyt h on З . 4/ s it e - p a c kages
Req u i re s : doc ut i l s , J i n j a 2 , Pygment s
Name : F l a s k
Ve r s ion : 0 . 10 . 1
Locat ion : / u s r/ lo c a l / l i b / pyt h on З . 4/ s it e - pa c kages
Req u i re s : Werkzeug. J i n j a 2 , i t s d a nge rou s
Команда pyvenv
Рассмотрим пример , который поможет вам научиться эффективно
использовать средство pyvenv. Прежде чем использовать этот инстру
мент, важно , чтобы вам был понятен смысл команды pyt h o n З , которую
вы вводите в командной строке своей системы. На моем компьюте
ре pyt honЗ располагается в каталоге / u s r/ lo c a l / b i n и запускает вер
сию 3 . 4 . 2 (см . раздел "Рекомендация 1 . Следите за тем , какую версию
Python вы используете").
$ wh i c h pyt honз
/ u s r/ lo c a l / b i n / pythonз
$ pythonЗ - - vers ion
Pyt hon 3 . 4 . 2
240 Гяава 7
таю.
$ s o u r c e b i n / a c t ivate
( myp roj ect ) $
Как только модуль pyt z установлен , я могу убедиться в том , что он ра
ботает, используя ту же тестовую команду импорта.
( myp roj ect ) $ pyt honЗ - с ' import pyt z '
( myp roj e ct ) $
pyt z = = 2014 . 4
req u e st s = = 2 . 3 . 0
# prod_ma i n . py
T E SТING = F a l se
import d b_connect ion
db = d b_c o n n e ct ion . Dat a b a s e ( )
# d b_c on n e c t ion . py
import _ma in_
c l a s s Test i ngDat a b a s e ( ob j e c t ) :
#
if _ma i n_ . T ESTING :
Dat a b a s e Test i n gData b a s e
=
else :
Dat a b a s e Rea lDat a b a s e
Производство 247
Примечание
К а к тол ько в а ш и с р еды раз ве ртыван и я н а ч и на ют услож няться , сто и т подума ть о
том , чтобы вы н ести и х и з конста н т Pythoп (н а под об и е T E S T I NG) в отд ел ь н ы е ко н
ф игура ци онные файлы. Та к и е и нструм енты , к а к вст р оен н ы й м одул ь c onfigp a r s e r ,
по з воля ют п одде ржи вать п рои з в одственные кон ф и гур а ци и отдел ьно от кода -
осо бенность , име ю щ а я кл ю чев о е з н а че н и е дл я сотруд н и честв а с о пе р ати вны м пе р
со н а ло м .
else :
Dat a b a s e Pos ixDat a ba s e
»>
5
5
print ( rep r ( a ) )
»>
' \х07 '
»>
5
• 5'
»>
5
'5'
250 ГJ1ава 8
obj = OpaqueC l a s s ( l , 2 )
p r i n t ( obj )
>»
<�ma i n� . Op a q u eC la s s obj e c t a t 0х107880Ь а 8 >
def �repr� ( s e l f ) :
ret u rn ' Bette rC l a s s ( %d , %d ) ' % ( s e lf . x , s e l f . y )
»>
Bet t e rC l a s s ( l , 2 )
Opaq u eC l a s s .
Производство 251
obj = OpaqueC l a s s ( 4 , 5 )
p rint ( obj . �d i ct�>
»>
{ ' у ' : 5 , ' х ' : 4}
# ut i l s_t e s t . py
from un ittest import Testca s e , ma i n
from ut i l s impo rt to_s t r
c l a s s Ut i l sTest C a s e ( TestCa s e ) :
def test_to_st r_byt e s ( s e lf ) :
s e lf . a s s e rt E q u a l ( ' h e l lo ' , t o_st r ( b ' h e l lo ' ) )
ma i n ( )
Примечание
Д руга я ра с п р ост ра ненн а я п ракти ка п р и н а п и с а н и и тестов - это и с пол ь з ов а н и е
ф и кти вных фу нкц и й и кл а ссов для со з да н и е загл уш ек. С этой целью Pythoп З п р едо
ста вляет встр оен н ы й м одул ь u n i t t e s t . moc k , та кже досту п н ы й для Python 2 в в и де
п акета с откр ыты м и сходны м кодо м.
П римечание
В з а в и с имо с ти от п ро е кта , уд о б н о о п р едел я ть тес т ы , у п р а вл яе м ые да н н ы ми, ил и
о бъед и ня ть тест ы в р азл ич н ы е на бор ы дл я п ро ве рки родс твен н ых в и до в фу н к цио
на л ь н ос ти . Ос о бен н о п ол е з н ы ми дл я эти х цел ей могут б ы ть отч еты о п окр ы ти и кода
и д ру г и е п родв и н ут ые ва ри а н ты и с п ол ьзо ван и я , а та кже п а к ет ы с откр ы ты м и сход
н ы м ко дом п о s е (htt p : / / no s e . r e a d t h e d o c s . o rg/) и p yt e s t (htt p : / / pyt e s t .
o rg/).
max_s i z e = 10 * * 4
data = [ ra n d i nt ( 0 , max_s i ze ) for _ i n range ( max_s i z e ) ]
t e s t = lambd a : i n sertion_so rt ( d at a )
П римечание
В п ро цессе п роф ил и ро ва н и я п рограмм ы с л едите за те м, что б ы и зм е р е н и я относ и
л и с ь им е н н о к в аш е му коду, а н е к в н е ш н им с и с те мам. О с о б о е в н има н и е об ра ща й те
н а фу н к ц ии, котор ы е п олуча ют до с туп к сети ил и р ес ур с ам н а ди с ке . И х вли я н и е н а
длител ь н о с ть в ы п ол не н и я п рогр а мм ы може т б ыть с у щ ес т ве н н ы м из - за м е дл е нн о й
ра б оты с оответс т вую щ и х б азо в ы х с и с те м . Е с л и ва ша п рограмма и с п ользуе т к е ш иро
в а н и е , ма с кирую щее заде ржк и, в оз н и ка ю щ и е п ри за грузке в н е шн и х р ес ур с о в н а п о
до б и е ука за н н ы х, в ам до п ол н ите льно с л е дуе т у б е диться в до с таточ н ом н а п ол н е н и и
ке ша, п р е жд е ч е м п ри с ту п ать к п роф ил и ро ва н и ю .
Ниже мы создадим экземпляр объекта P rofi l e из модуля c P rofile и
выполним с его помощью тестовую функцию. используя метод ru п c a l l ( ) .
p rofi l e r = P rofi l e ( )
p rofi l e r . ru n c a l l ( t est )
d ef i n s e rt_va l ue ( a rray , v a l ue ) :
i = b i s e ct_l eft ( a r ray , v a l u e )
a r ray . in s e rt ( i , va l u e )
d ef f i r st_f u n c ( ) :
for _ in range ( 1000 ) :
my_ut i l ity ( 4 , 5 )
def second_fun c ( ) :
for _ i n range ( 10 ) :
my_ut i l ity ( l , 3 )
for _ in range ( 20 ) :
f i r st_fu n c ( )
s e c o n d _fu n c ( )
Ordered Ьу : c u m u l at ive t i me
»>
F u n ction wa s c a l led Ьу . . .
n c a l l s tott ime c umt i me
ma i n . py : 176 ( my_program ) <-
ma i n . py : 168 ( f i r st_fu n c ) <- 20 0 . 00 5 0 . 206 ma i n . py : 17 6 ( my_program )
ma i n . py : lбl ( my_ut i l ity ) < - 20000 0 . 202 0 . 202 m a i n . py : 168 { f i r st_fu n c )
200 0 . 002 0 . 002 m a i n . py : 172 ( second_fu n c )
ma i n . py : 172 { second_fu n c ) < - 20 0 . 000 0 . 002 ma i n . py : 176 ( my_program )
262 Глава 8
import wa ste_memory
х = waste_memo ry . ru n ( )
found_obj e c t s = gc . get_obj e ct s ( )
p r i nt ( ' %d объектов после ' % l e n ( found_obj e c t s ) )
for obj i n fou nd_ob j e c t s [ : З ) :
p r i nt ( rep r ( obj ) [ : 100 ) )
»>
47 56 объектов до
14873 объе ктов после
<waste_memory . MyOb j ect obj ect at 0х106Зf6940 >
<waste_memo ry . MyOb j e c t obj ect at 0х106Зfб9 7 8 >
<waste_memo ry . MyOb j ect obj ect a t 0х106Зfб9Ь0 >
Здесь сразу можно увидеть, какие объекты играют главную роль в по
треблении памяти и в каких строках располагается исходный код, вы
деляющий память для них.
Кроме того, модуль t ra c emal loc обеспечивает вывод полной инфор
мации о трассировке стека для каждого блока (вплоть до количества
фреймов , переданных методу s t a rt ( ) ) .
Выведем данные трассировки стека для основного потребителя па
мяти в программе.
# with_t ra c e . py
# • • •
»>
F i le " wast e_memory . py " , l i n e б
s e lf . x = os . u ra nd om ( 100 )
F i le " wa ste_memory . py " , l i n e 1 2
obj = MyObj ec t ( )
F i le " wa st e_memory . py " , l i n e 19
deep_va l u e s . append ( get_data ( ) )
F i le " with_t r a c e . py " , l i n e 10
х = wa ste_memory . ru n ( )
А s
API 224 Shift JIS 24
ASCII 26, 34
u
в Unicode 24. 34
B i g5 24 UTC 202
UТF-8 24. 26, 34
с
CPython 1 56 , 262 А
Алгоритм дырявого ведра 1 24
D Атрибут 22
Docstrings 76, 2 1 7
в
G Версии Python 1 9
GIL 1 56, 1 6 1 . 1 83 Взаимоисключающая блоки-
ровка 1 56
J Визуальный шум 69
JSON 50 Внедрение зависимостей 235
Всемирное скоординированное
L время 202
Latin- 1 24 Выражение-генератор 40
Вытесняющая многопоточ
м ность 1 56
MRO 1 0 1
г
о Генератор 62
ОRМ 1 46 отложенный 42
списков 36. 38
р Dюбальная блокировка интерпре
РЕР 8 2 1 . 23. 234 татора 1 56. 1 83
Pylint 23
Dюбальная область видимости 58
PyPI 2 1 4
Голодание потока 1 68
268 Предметный указатель
д Метакласс 1 1 9 , 1 40
Двоичный поиск 2 1 О Метод 22
append() 62
Декоратор 1 2 1 . 1 24 . 1 46. 1 89
_call_() 60, 92
Дескриптор 1 30 . 1 47 communicate() 1 52
Динамический импорт 236 decode() 24
Динамическое состояние 83 dump() 1 96
Документирование 2 1 7 encode() 24
Закрытый атрибут 1 09 _enter_() 1 92
Замыкание 56, 59 _exit_() 1 92
get() 27. 1 68
и __getattr_() 1 34
__getattribute_() 1 3 1 , 1 36
Именованный аргумент 78
__getitem_() 30
Интерактивный отладчик 255 index() 2 1 0
Исключение 22 1 islice() 35
AssertionError 253 _iter_() 66
AttributeError 1 36, 234 join() 1 70
IndexError 3 1 , 1 66 json . loads() 50
NameError 58 list() 62
OvarflowError 78 map() 96
Stoplteration 65, 66, 1 76 mro() 1 02
SyntaxError 25 1 _next_() 66
1)rpeError 26. 67 рор() 8 1
ZeroDivisionError 55, 78 put() 1 69
корневое 229 quantize() 2 1 3
обработка 49 read() 26, 49
распространение 49, 229 reduce() 96
Итератор 66, 2 1 0 _repr_() 2 50
run() 1 68
к runcall() 258
Ключевое слово send() 1 74
cls 22 _setitem_() 30
global 59 sort() 56, 89
nonlocal 59 super() 1 04
self 22 write() 26
yield 1 94, 1 95 Модуль 1 6
Когерентность 1 56 asyncio 1 6 1
Конвейер 1 65 Ьisect 2 1 0
Константа 22 collections 87, 207
collections. abc 94. 1 1 7
Куча 209
concurrent . futures 1 84
contextlib 1 92
л
copyreg 1 98
Лямбда-выражение 89 datetime 204
decimal 2 1 3
м fractions 2 1 4
Менеджер контекста 1 93 functools 1 9 1
Предметный указатель 269
КАРМАННЫИ СПРАВОЧНИК
ПЯТОЕ ИЗДАНИЕ
Марк Лутц
Э т о т к р ат к и й с п р а в о ч н и к rю
Python с о с т а в л е н с у ч етом
в ер с и й 3.4 и 2 .7 и очен ь
удо бен д л я н а в еден и я
быстр ы х с п равок п р и
разработке п р о г ра м м н а
Python . В л а ко н и ч н о й
ф о р м е з д е с ь п редс т а в л е н ы
в с е необход и м ы е с в еден и я
о т и п а х да н н ы х и о п е р аторах
Python , с п е ц и ал ь н ы х ме тод а х
п е р е г р у з к и о перат о р о в ,
в с т р о е н н ы х фу н к ц и я х
и и с к л ю ч е н и я х , н а и более
у н о т реби тел ь н ы х с т а н д а рт н ы х
б и б л и от е ч н ы х модул я х
и д ру г и х п р и м еч ател ь н ы х
я з ы к о в ы х с редс т в а х
Pythoн , в том ч ис л е и дл я
объект н о - о р ие н т и р о в а н ного
www.williamspuЬlishing.com п ро г р а м м и ро в а н и я .
С п р а в о ч н и к рас с ч и т а н н а
ш и р о к и й кру г •1 и тател е й ,
и н т е р е с у ю щ и хс я
п ро г р а м м и ро в а н и е м на Python .
УЭСЛИ Ж. ЧАН
-
с помощ ь ю каркаса Django
и облач н ы х в ы ч и сле н и й на
платформе G oog le Арр Engine ,
а также п рограм м и рова н ие
www.williamspuЬlishing.com на я з ы ке Java в среде Jython
и способы уста новлен и я
соед и не н и й с с о ц и ал ьн ы м и
сетя м и Twitter и Goog l e +.
К н и га п редста вл яет
собой цен н ы й источ н и к
з н а н и й п о я з ы ку Python
и п ред н азначена дл я
п рогра м м и стов всех уровне й .