Несколько советов, приемов и распространенных ошибок¶

Это небольшое резюме идей, советов и часто встречающихся ошибок, которые могут быть полезны начинающим Python.

Это небольшое резюме идей, советов и часто встречающихся ошибок, которые могут быть полезны начинающим Python.

Функции¶

Функции помогают нам в мысленном разбиении на части: они позволяют нам группировать утверждения для высокоуровневой цели, например, функция для сортировки списка элементов, функция, заставляющая черепаху рисовать спираль, или функция для вычисления среднего и стандартное отклонение некоторых измерений.

Есть два типа функций: плодотворные или возвращающие значение функции, которые вычисляют и возвращают значение , и мы используем их, потому что нас в первую очередь интересует значение, которое они возвращают. Пустые (бесплодные) функции используются, потому что они выполняют действия, которые мы хотим выполнить - например, заставить черепаху нарисовать прямоугольник или напечатать первую тысячу простых чисел. Они всегда возвращают None - специальное фиктивное значение.

Совет: None не является строкой

Такие значения, как None , True и False , не являются строками: они являются специальными значениями в Python и находятся в списке ключевых слов, который мы привели в главе 2 (Переменные, выражения и инструкции). Ключевые слова особенные в языке: они являются частью синтаксиса. Таким образом, мы не можем создать собственную переменную или функцию с именем True - мы получим синтаксическую ошибку. (Встроенные функции не имеют таких привилегий, как ключевые слова: мы можем определить нашу собственную переменную или функцию с именем len , но было бы глупо это сделать!)

Помимо плодотворных / пустых семейств функций, в Python есть два варианта оператора return : один, который возвращает полезное значение, а другой, который ничего не возвращает, или None . И если мы дойдем до конца какой-либо функции и не выполнили явно какой-либо оператор return , Python автоматически вернет значение None .

Совет: поймите, что функция должна возвращать

Возможно, ничего - некоторые функции существуют исключительно для выполнения действий, а не для вычисления и возврата результата. Но если функция должна возвращать значение, убедитесь, что все пути выполнения действительно возвращают значение.

Чтобы функции были более полезными, им задаются параметры . Таким образом, функция, заставляющая черепаху рисовать квадрат, может иметь два параметра: один для черепахи, которая должна рисовать, а другой - для размера квадрата. См. Первый пример в главе 4 (Функции) - эту функцию можно использовать с любой черепахой и квадратом любого размера. Таким образом, это гораздо более общий характер, чем функция, которая всегда использует конкретную черепаху, например tess, для рисования квадрата определенного размера, например 30.

Совет: используйте параметры для обобщения функций

Поймите, какие части функции будут жестко запрограммированы и неизменяемы, а какие должны стать параметрами, чтобы их мог настроить вызывающий функцию.

Совет: попробуйте связать функции Python с уже известными нам идеями.

В математике мы знакомы с такими функциями, как f (x) = 3x + 5 . Мы уже понимаем, что когда мы вызываем функцию f (3), мы устанавливаем некоторую связь между параметром x и аргументом 3. Попробуйте провести параллели с передачей аргументов в Python.

Тест: функция f (z) = 3z + 5 такая же, как функция f выше?

Проблемы с логикой и потоком управления¶

Мы часто хотим знать, выполняется ли какое-либо условие для любого элемента в списке, например, «есть ли в списке какие-нибудь нечетные числа?» Это частая ошибка:

Можем ли мы заметить здесь две проблемы? Как только мы выполним возврат , мы выйдем из функции. Так что логика высказывания «Если я найду нечетное число, я могу вернуть True » - это нормально. Однако мы не можем вернуть False после просмотра только одного элемента - мы можем вернуть False только в том случае, если мы просмотрели все элементы, и ни один из них не является странным. Таким образом, строки 6 там не должно быть, а строка 7 должна быть вне цикла. Чтобы найти вторую проблему выше, подумайте, что произойдет, если вы вызовете эту функцию с аргументом, который является пустым списком. Вот исправленная версия:

Этот «эврика», или «короткозамкнутый» стиль возврата из функции, как только мы уверены, каким будет результат, впервые был рассмотрен в Разделе 8.10, в главе о строках.

Он предпочтительнее этого, который также работает правильно:

Недостатком производительности этого метода является то, что он просматривает весь список, даже если он знает результат очень рано.

Совет: подумайте об условиях возврата функции

Нужно ли мне во всех случаях смотреть на все элементы? Могу ли я срезать путь и быстро выйти? В каких условиях? Когда мне нужно будет изучить все предметы в списке?

Код в строках 7-10 тоже можно подтянуть. Выражение count>0 дает логическое значение True или False . Значение можно использовать непосредственно в операторе возврата . Таким образом, мы могли бы вырезать этот код и получить просто следующее:

Хотя этот код более жесткий, он не так хорош, как тот, в котором короткое замыкание вернулось, как только было найдено первое нечетное число.

Совет: обобщите использование логических значений

Зрелые программисты не будут писать if is_prime (n) == True: вместо этого они могли бы сказать if is_prime (n): думайте в более общем плане о логических значениях, а не только в контексте операторов if или while . Как и арифметические выражения, они имеют собственный набор операторов ( and , or , not ) и значений ( True , False ) и могут быть присвоены переменным, помещены в списки и т. Д. Хорошим ресурсом для улучшения использования логических значений является http: //en.wikibooks.org/wiki/Non-Programmer%27s_Tutorial_for_Python_3/Boolean_Expressions

  • Как бы мы могли адаптировать это, чтобы сделать другую функцию, которая возвращает True, если все числа нечетные? Можете ли вы по-прежнему использовать стиль короткого замыкания?
  • Как бы мы могли адаптировать его для возврата True, если хотя бы три числа нечетные? Замкните обход, когда будет найдено третье нечетное число - не проходите весь список, если нам не нужно.

Локальные переменные¶

Функции вызываются или активируются, и пока они заняты, они создают свой собственный стековый фрейм, содержащий локальные переменные. Локальная переменная - это переменная, принадлежащая текущей активации. Как только функция возвращается (будь то из явного оператора return или из-за того, что Python дошел до последнего оператора), фрейм стека и его локальные переменные уничтожаются. Важным следствием этого является то, что функция не может использовать свои собственные переменные для запоминания любого состояния между различными активациями. Он не может подсчитать, сколько раз он был вызван, или не забыть переключать цвета между красным и синим, ЕСЛИ он не использует глобальные переменные. Глобальные переменные сохранятся даже после выхода из нашей функции, поэтому они являются правильным способом сохранения информации между вызовами.

Этот фрагмент предполагает, что наша черепаха - это тэсс . Каждый раз, когда мы вызываем h2 (), он поворачивает, рисует и увеличивает глобальную переменную sz . Python всегда предполагает, что присвоение переменной (как в строке 7) означает, что нам нужна новая локальная переменная, если мы не предоставили глобальное объявление (в строке 4). Таким образом, отсутствие глобального объявления означает, что это не работает.

Совет: локальные переменные не сохраняются при выходе из функции

Используйте визуализатор Python, подобный тому, что находится на http://netserv.ict.ru.ac.za/python3_viz, чтобы получить четкое представление о вызовах функций, фреймах стека, локальных переменных и возвращаемых функциях.

Совет: присвоение в функции создает локальную переменную

Любое присвоение переменной внутри функции означает, что Python создаст локальную переменную, если мы не переопределим с помощью global .

Функции обработчика событий¶

В нашей главе, посвященной обработке событий, были показаны три различных типа событий, с которыми мы можем справиться. У каждого из них есть свои тонкости, которые могут сбить нас с толку.

  • Обработчики событий - это пустые функции - они не возвращают никаких значений.
  • Они автоматически вызываются интерпретатором Python в ответ на событие, поэтому мы не видим код, который их вызывает.
  • Событие щелчка мыши передает два аргумента координат своему обработчику, поэтому, когда мы пишем этот обработчик, мы должны предоставить два параметра (обычно называемые x и y ). Таким образом обработчик узнает, где произошел щелчок мышью.
  • Обработчик события нажатия клавиши должен быть привязан к клавише, на которую он реагирует. При использовании нажатий клавиш есть дополнительный беспорядочный шаг: мы должны не забыть запустить wn.listen () до того, как наша программа получит какие-либо нажатия клавиш. Но если пользователь нажимает клавишу 10 раз, обработчик будет вызван десять раз.
  • Использование таймера для создания события, датированного будущим, вызывает только один вызов обработчика. Если нам нужны повторяющиеся периодические активации обработчика, то из обработчика мы вызываем wn.ontimer (.), Чтобы настроить следующее событие.

Обработка строк¶

Есть только четыре действительно важных операции со строками, и мы сможем сделать что угодно. Есть еще много полезных методов (мы назовем их сахарным покрытием), которые могут облегчить жизнь, но если мы сможем без проблем работать с основными четырьмя операциями, у нас будет отличное заземление.

  • len (str) находит длину строки.
  • str [i] операция с индексом извлекает i-й символ строки как новую строку.
  • str [i: j] операция среза извлекает подстроку из строки.
  • str.find (target) возвращает индекс, в котором цель встречается в строке, или -1, если она не найдена.

Поэтому, если нам нужно знать, встречается ли «змея» как подстрока в s , мы могли бы написать

Было бы неправильно разбивать строку на слова, если бы нас не спросили, встречается ли в строке слово «змея».

Предположим, нас просят прочитать некоторые строки данных и найти определения функций, например: def some_function_name (x, y):, и нас дополнительно просят изолировать и работать с именем функции. (Скажем, распечатайте.)

Эти идеи можно расширить:

  • Что, если функция def была с отступом и не начиналась с столбца 0? Код потребует небольшой корректировки, и мы, вероятно, захотим убедиться, что все символы перед позицией def_pos были пробелами. Мы бы не хотели поступать неправильно с такими данными: # Мне определенно нравится Python!
  • Мы предположили, что в строке 3 мы найдем открывающую скобку. Возможно, потребуется проверить, что мы сделали!
  • Мы также предположили, что между ключевым словом def и началом имени функции был ровно один пробел . Это не будет хорошо работать для def f (x)

Как мы уже упоминали, существует гораздо больше методов, «покрытых сахаром», которые позволяют нам легче работать со строками. Существует метод rfind , например find , который выполняет поиск от конца строки в обратном направлении. Это полезно, если мы хотим найти последнее вхождение чего-либо. В нижних и верхних методах могут сделать преобразование регистра. А метод разделения отлично подходит для разбиения строки на список слов или на список строк. В этой книге мы также широко использовали метод форматирования . Фактически, если мы хотим попрактиковаться в чтении документации Python и самостоятельном изучении некоторых новых методов, строковые методы - отличный ресурс.

  • Предположим, любая строка текста может содержать не более одного URL-адреса, который начинается с «http: //» и заканчивается следующим пробелом в строке. Напишите фрагмент кода для извлечения и распечатайте полный URL-адрес, если он присутствует. (Подсказка: прочтите документацию по find . Требуются дополнительные аргументы, поэтому вы можете установить начальную точку, с которой будет выполняться поиск.)
  • Предположим, что строка содержит не более одной подстроки « ». Напишите фрагмент кода для извлечения и печати части строки между угловыми скобками.

Циклы и списки¶

Компьютеры полезны, потому что они могут точно и быстро повторять вычисления. Таким образом, циклы станут центральной особенностью почти всех программ, с которыми вы сталкиваетесь.

Совет: не создавайте ненужных списков

Списки полезны, если вам нужно сохранить данные для последующих вычислений. Но если вам не нужны списки, вероятно, лучше не создавать их.

Вот две функции, которые генерируют десять миллионов случайных чисел и возвращают сумму чисел. Они оба работают.

По каким причинам здесь предпочтение отдается второй версии? (Подсказка: откройте на своем компьютере такой инструмент, как Performance Monitor, и посмотрите, как используется память. Насколько большим вы можете составить список, прежде чем вы получите фатальную ошибку памяти в сумме 1 ?)

Аналогичным образом при работе с файлами у нас часто есть возможность прочитать все содержимое файла в одной строке или мы можем читать по одной строке за раз и обрабатывать каждую строку по мере ее чтения. По очереди - это более традиционный и, возможно, более безопасный способ делать что-либо - вы сможете работать с комфортом независимо от размера файла. (И, конечно же, этот режим обработки файлов был необходим в старые времена, когда компьютерная память была намного меньше.) Но иногда вы можете обнаружить, что режим «весь файл за один раз» удобнее!