Чистыйкод дляпродолжающи х
Скачать 7.85 Mb.
|
Условные выражения: «некрасивый» тернарный оператор Python Тернарные операторы (в Python их официально называют условными выражени- ями, или тернарными выражениями выбора) вычисляют выражение и выбирают в качестве результата одно из двух значений в зависимости от условия. Обычно это делается следующей питонической командой if - else : >>> # Пример питонического кода. >>> condition = True >>> if condition: ... message = 'Access granted' ... else: ... message = 'Access denied' >>> message 'Access granted' Тернарный означает, что оператор получает три входных значения, но в програм- мировании оно синонимично условному выражению. Условные выражения также предлагают более компактное однострочное решение, соответствующее этому паттерну. В Python они реализуются странным расположением ключевых слов if и else : >>> valueIfTrue = 'Access granted' >>> valueIfFalse = 'Access denied' >>> condition = True >>> message = valueIfTrue if condition else valueIfFalse ❶ >>> message 'Access granted' >>> print(valueIfTrue if condition else valueIfFalse) ❷ 'Access granted' >>> condition = False Условные выражения: «некрасивый» тернарный оператор Python 131 >>> message = valueIfTrue if condition else valueIfFalse >>> message 'Access denied' Выражение valueIfTrue if condition else valueIfFalse ❶ дает результат valueIfTrue , если переменная condition равна True . Если переменная condition содержит False , то выражение дает результат valueIfFalse . Гвидо ван Россум шутливо описывал спроектированный им синтаксис как «намеренно уродливый». Во многих языках с тернарным оператором сначала указывается условие, затем значение для True и потом значение для False . Условное выражение может использоваться везде, где может применяться выражение или значение, включая аргумент вызова функции ❷ Почему этот синтаксис был включен в Python 2.5, хотя он и нарушает первую реко- мендацию «красивое лучше, чему уродливое»? К сожалению, многие программисты используют тернарные операторы, несмотря на их неудобочитаемость, и хотят, чтобы этот синтаксис поддерживался в Python. Злоупотребление ускоренным вычислением логических операторов позволяет создать некую разновидность тернарного операто- ра. Выражение condition and valueIfTrue or valueIfFalse дает результат valueIfTrue , если condition содержит True , и valueIfFalse , если condition содержит False (кроме одного важного случая). Введите следующий фрагмент в интерактивной оболочке: >>> # Пример непитонического кода. >>> valueIfTrue = 'Access granted' >>> valueIfFalse = 'Access denied' >>> condition = True >>> condition and valueIfTrue or valueIfFalse 'Access granted' У этого «псевдотернарного» оператора condition and valueIfTrue or valueIfFalse есть один неочевидный дефект: если valueIfTrue содержит квазиложное значение (например, 0 , False , None или пустая строка), выражение неожиданно дает результат valueIfFalse , хотя condition содержит True Но программисты продолжают использовать этот фиктивный тернарный опера- тор, а вопрос «почему в Python нет тернарного оператора?» постоянно приходится слышать разработчикам реализации Python. Условные выражения были созданы для того, чтобы программисты перестали требовать тернарный оператор и не ис- пользовали псевдотернарный оператор с его скрытыми ошибками. Но условные выражения достаточно уродливы, чтобы отвадить программистов от их примене- ния. И хотя «красивое лучше, чем уродливое», «уродливый» тернарный оператор Python можно считать примером того, когда практичность важнее безупречности. Условные выражения вряд ли можно назвать питоническими, но и однозначно считать их непитоническими тоже нельзя. Если вы пользуетесь ими, избегайте вложения условных выражений в другие условные выражения: 132 Глава 6.Написание питонического кода >>> # Пример непитонического кода. >>> age = 30 >>> ageRange = 'child' if age < 13 else 'teenager' if age >= 13 and age < 18 else 'adult' >>> ageRange 'adult' Вложенные условные выражения — хороший пример того, что плотная одностроч- ная конструкция может быть технически правильной, но плохо восприниматься при чтении. Работа со значениями переменных При написании кода часто возникает необходимость в проверке и изменении значений, хранящихся в переменных. В Python это можно сделать несколькими способами. Рассмотрим пару примеров. Сцепление операторов присваивания и сравнения Когда требуется проверить, принадлежит ли число некоторому диапазону, можно воспользоваться логическим оператором and в следующей конструкции: # Пример непитонического кода. if 42 < spam and spam < 99: Но Python позволяет формировать цепочки операторов сравнения, чтобы вам не приходилось использовать оператор and . Следующий код эквивалентен предыду- щему примеру: # Пример непитонического кода. if 42 < spam < 99: В цепочки можно объединять и операторы присваивания. Например, одно значение можно присвоить нескольким переменным в одной строке кода: >>> # Пример питонического кода. >>> spam = eggs = bacon = 'string' >>> print(spam, eggs, bacon) string string string Чтобы удостовериться, что все три переменные содержат одинаковые значения, можно воспользоваться оператором and или создать цепочку из операторов == для проверки равенства: >>> # Пример питонического кода. >>> spam = eggs = bacon = 'string' Итоги 133 >>> spam == eggs == bacon == 'string' True Сцепление операторов — небольшая, но полезная форма сокращенной записи в Python. Но при неправильном использовании операторы могут создать проблемы. В главе 8 демонстрируются некоторые примеры, когда неправильное применение операторов может создать неожиданные ошибки в вашем коде. Проверка того, что переменная содержит одно из нескольких значений Иногда возникает ситуация, обратная описанной в предыдущем разделе: требуется проверить, содержит ли переменная одно из нескольких возможных значений. Для этого можно воспользоваться оператором or (как в выражении spam == 'cat' or spam == 'dog' or spam == 'moose' ). Со всеми избыточными частями spam == выражение становится излишне громоздким. Вместо этого можно объединить несколько значений в кортеж и проверить, со- держится ли значение переменной в кортеже, оператором in , как в следующем примере: >>> # Пример питонического кода. >>> spam = 'cat' >>> spam in ('cat', 'dog', 'moose') True Этот код не только более понятен, но и по данным timeit работает чуть быстрее. Итоги Во всех языках программирования существуют собственные приемы и «передо- вые» практики. В этой главе я рассказал о конкретных способах написания пито- нического кода, которые создали программисты для оптимального использования синтаксиса Python. В основе питонического кода лежат 20 тезисов документа «Дзен Python», которые отражают принципы написания кода на Python. Эти положения следует рассма- тривать как субъективное мнение; они не являются абсолютно необходимыми для написания программ на Python, но помнить о них безусловно стоит. Значимые отступы Python (не путайте со значимыми пробелами!) вызывают больше всего протестов со стороны начинающих программистов. И хотя почти во всех языках программирования отступы используются для удобочитаемости кода, Python требует, чтобы отступы заменяли более привычные фигурные скобки, при- меняемые в других языках. 134 Глава 6.Написание питонического кода Модуль Python timeit позволяет быстро профилировать время выполнения кода; это всегда лучше, чем просто предположить, что какой-то код работает быстрее. И хотя многие программисты на Python используют конструкцию range(len()) для циклов for , функция enumerate() предоставляет более чистый синтаксис для получения индекса и значения при переборе последовательности. Аналогичным образом команда with предоставляет более чистый и надежный механизм работы с файлами по сравнению с ручными вызовами open() и close() . Команда with гарантирует, что метод close() будет вызван в любой ситуации, когда управление выйдет за пределы блока команды with В Python предусмотрено несколько способов интерполяции строк. Изначально спецификатор преобразования %s помечал позиции, в которых строки должны вставляться в исходную строку. Современный подход для версии Python 3.6 основан на использовании f-строк. У f-строк строковый литерал помечается префиксом f , а фигурные скобки отмечают, где в строке могут размещаться строки (или целые выражения). Синтаксис [:] для создания поверхностных копий списков выглядит немного странно и не может однозначно считаться питоническим, но он стал популярен в качестве способа быстрого создания поверхностных копий списков. У словарей определены методы get() и setdefault() для выполнения операций с несуществующими ключами. Также словарь collections.defaultdict использует значение по умолчанию для несуществующих ключей. Так как в Python нет команды switch , использование словаря позволяет компактно записать эквивалент switch без нескольких команд if - elif - else ; при выборе между двумя значениями также можно использовать тернарный оператор. Цепочка операторов == позволяет проверить, что несколько переменных равны друг другу, а оператор in — проверить, что переменная имеет одно из нескольких возможных значений. В этой главе были рассмотрены некоторые идиомы языка Python, а также даны рекомендации относительно того, как писать более питонический код. В следующей главе рассматриваются некоторые проблемы и ловушки, в которые часто попадают начинающие. 7 Жаргон программистов В своем комиксе XKCD «Up Goer Five» (https://xkcd. com/1133/) создатель веб-комиксов Рэндалл Мунро (Randall Munroe) показал техническую схему ракеты Saturn V, исполь- зуя только тысячу самых распространенных английских слов. Технические термины он описал предложениями, понятными даже ребенку. Но также он наглядно продемонстрировал, почему нельзя все объяснять простыми выражениями. «Штуковина, которая по- может людям очень быстро сбежать, если возникла проблема, все горит и они решают не лететь в космос» для непосвященной аудитории более понятна, чем «запуск системы эвакуации». Однако для инженеров NASA в их повседневной работе все это слишком многословно. Они скорее воспользуются сокращением LES (Launch Escape System). И хотя компьютерный жаргон может показаться неопытным программистам устра- шающим и запутанным, сокращения необходимы. Некоторые термины в Python и в области разработки программного обеспечения имеют тонкие смысловые разли- чия, и даже опытные разработчики иногда ошибочно используют их как синонимы. Технические определения таких терминов могут различаться в разных языках про- граммирования, но здесь я рассказываю о терминах в Python. Вы получите широкое, хотя и не глубокое понимание стоящих за ними концепций языка программирования. Я полагаю, что вы еще не знакомы с классами и объектно-ориентированным про- граммированием (ООП). Поэтому здесь я кратко расскажу о классах и другом ООП-жаргоне, а о самом жаргоне более подробно мы поговорим в главах 15–17. Определения Когда в одной комнате оказываются хотя бы два программиста, вероятность споров о семантике достигает 100%. Язык динамичен, а люди распоряжаются 136 Глава 7.Жаргон программистов словами, но не наоборот. Некоторые разработчики используют одни и те же термины несколько в разных смыслах, но хорошо знать терминологию все равно полезно. В этой главе я расскажу о терминах и их взаимосвязях. Если вам пона- добится список терминов в алфавитном порядке, обращайтесь к официальному глоссарию Python по адресу https://docs.python.org/3/glossary.html; вы найдете здесь канонические определения 1 Несомненно, некоторые программисты, прочитав определения в этой главе, при- помнят особые случаи или исключения, но придираться можно бесконечно. Эта глава не была задумана как исчерпывающее описание; я дал доступные определения, пусть даже не идеальные. Но всегда можно узнать что-то новое, как это обычно бывает в программировании. Язык Python и интерпретатор Python Язык программирования Python обязан своим названием не змее, а британской комедийной группе Monty Python (хотя в документации и учебниках Python ис- пользуются отсылки как к Monty Python, так и к змеям). В области программиро- вания название Python тоже имеет два значения. Когда мы говорим «Python запускает программу» или «Python выдает исклю- чение», речь идет об интерпретаторе Python (Python interpreter) — программе, которая читает текст из файла .py и выполняет содержащиеся в нем инструк- ции. Если вы встречаете выражение «интерпретатор Python», то почти всегда подразумевается CPython — интерпретатор Python, сопровождением которого занимается фонд Python Software Foundation, доступный на сайте https://www. python.org. CPython является реализацией (implementation) языка Python (то есть программой, написанной для выполнения спецификации), однако существуют и другие. Хотя CPython написан на языке программирования C, реализация Jython написана на Java для выполнения сценариев Python, совместимых с программами Java. PyPy — JIT-компилятор (just-in-time compiler) для Python, компилирующий программы непосредственно в процессе их выполнения, — на- писан на Python. Все эти реализации выполняют исходный код, написанный на языке программи- рования Python; именно это мы имеем в виду, говоря: «Это программа Python» или «Я изучаю Python». В идеале любой интерпретатор Python способен вы- полнить любой исходный код, написанный на языке Python; тем не менее в ре- альном мире всегда будут существовать небольшие несовместимости и различия 1 В этой главе все термины глоссария даются на русском и в скобках на английском языке. — Примеч. ред. Определения 137 между интерпретаторами. CPython называется эталонной реализацией (reference implementation) языка Python, потому что, если существуют различия между тем, как код Python интерпретируется CPython и другим интерпретатором, поведение CPython считается каноническим и правильным. Сборка мусора Во многих ранних языках программисту приходилось приказывать программе вы- делять, а затем освобождать память для структур данных по мере необходимости. Ручное выделение памяти становилось источником многих ошибок, таких как утечка памяти (когда программист забывал освободить выделенную память) или двойное освобождение (когда программисты освобождали одну и ту же область памяти дважды, что приводило к повреждению данных). Для предотвращения этих ошибок в Python существует сборка мусора (garbage collection) — механизм автоматического управления памятью, который отсле- живает выделение и освобождение памяти, чтобы программисту не приходилось заниматься этим самому. Сборку мусора можно рассматривать как освобождение памяти, потому что она делает память доступной для новых данных. Например, введите следующую команду в интерактивной оболочке: >>> def someFunction(): ... print('someFunction() called.') ... spam = ['cat', 'dog', 'moose'] >>> someFunction() someFunction() called. При вызове someFunction() Python выделяет память для списка ['cat', 'dog', 'moose'] . Программисту не нужно самостоятельно вычислять, сколько байтов памяти следует запросить, потому что Python делает это автоматически. Сборщик мусора Python освобождает локальные переменные при выходе из функции, чтобы занимаемая ими память стала доступна для других данных. Сборка мусора суще- ственно упрощает программирование и повышает его надежность. Литералы Литерал (literal) — текст в исходном коде программы, определяющий фиксиро- ванное типизованное значение. В следующем примере: >>> age = 42 + len('Zophie') фрагменты текста 42 и 'Zophie' определяют два литерала, целый и строковый. Литерал можно рассматривать как значение, буквально определяемое в исходном 138 Глава 7.Жаргон программистов коде. Только встроенные типы данных могут иметь литеральные значения в ис- ходном коде Python, так что переменная age литеральным значением не является. В табл. 7.1 приведены примеры литералов Python. Таблица 7.1. Примеры литералов в Python Литерал Тип данных 42 Integer 3.14 Float 1.4886191506362924e+36 Float """Howdy!""" String r'Green\Blue' String [] List {'name': 'Zophie'} Dictionary b'\x41' Bytes True Boolean None NoneType Дотошные читатели заметят, что некоторые из моих примеров не являются лите- ралами в соответствии с официальной документацией языка Python. Формально -5 не является литералом в Python, потому что язык определяет знак «минус» ( - ) как оператор, применяемый к литералу 5 . Кроме того, True , False и None счита- ются ключевыми словами Python, а не литералами, тогда как [] и {} называются индикаторами (displays) или атомами (atoms) в зависимости от того, какую часть официальной документации вы просматриваете. Тем не менее литерал — распро- страненный термин, который будет использоваться профессиональными разработ- чиками во всех этих примерах. Ключевые слова В каждом языке программирования существует собственный набор ключевых слов. Ключевые слова Python образуют набор имен, которые резервируются как часть языка и не могут использоваться как имена переменных (то есть идентификаторы). Например, создать переменную с именем while не удастся, потому что ключевое слово while зарезервировано для использования в циклах while . Ниже приводится список ключевых слов Python для версии Python 3.9. Определения 139 and continue finally is raise as def for lambda return assert del from None True async elif global nonlocal try await else if not while break except import or with class False in pass yield Следует помнить, что ключевые слова Python всегда записываются на английском языке, они недоступны на других языках. Например, следующая функция содержит идентификаторы, записанные на испанском языке, но ключевые слова def и return остаются записанными на английском. def agregarDosNúmeros(primerNúmero, segundoNúmero): return primerNúmero + segundoNúmero К сожалению, английский язык доминирует в области программирования — и это определенная сложность для 6,5 миллиарда человек, которые на английском не говорят. |