Книга: Основы информационных технологий для неспециалистов: что происходит внутри машин
Назад: 6. Программные системы
Дальше: Часть III Коммуникации

7. Учимся программировать

Не просто играйте на своем телефоне, а пишите для него программы!
Барак Обама, президент США, декабрь 2013 года65
На своем курсе я немного учу программированию, поскольку считаю, что человеку осведомленному важно узнать об этом хоть немного – главным образом то, что порой удивительно тяжело заставить даже простые программы работать как положено. Чтобы преподать такой урок, нет ничего лучше, чем поручить студентам сразиться с компьютером – и они испытают прекрасное чувство достигнутой цели, когда их проект заработает в первый раз. Полезно также иметь достаточный опыт в программировании, чтобы насторожиться, если кто-то говорит, что писать код просто или что в какой-нибудь программе нет ошибок. Если вы целый день корпели над десятью строчками и едва добились нужного результата, то с обоснованным скептицизмом отнесетесь к утверждению, что приложение из миллиона строк будет завершено вовремя и без единого недочета. С другой стороны, бывают случаи, когда полезно знать, что не все задачи в программировании сложны – например, при найме консультанта.
Существует целая тьма языков. Какой из них вам следует изучить в первую очередь? Если вы хотите написать программу для своего телефона, как призывал нас президент Обама, вам понадобится Java для Android или Swift для iPhone. Оба этих ЯП могут освоить новички, но они сложны для повседневного использования, да и в создании кода для смартфона много нюансов. Scratch, система визуального программирования от МТИ, очень хороша для детей, но на ней невозможно писать крупные или сложные программы.
В этой главе я кратко расскажу о двух ЯП – JavaScript и Python. Оба широко используются как профессиональными программистами, так и любителями. Они просты в освоении на начальном уровне, широко применимы и масштабируемы при создании более крупных программ.
Язык JavaScript включен в каждый браузер, поэтому никакое ПО скачивать не нужно. Написав программу, вы сможете использовать ее на собственных веб-страницах, чтобы показать друзьям и родственникам. Сам по себе язык простой – даже при скромном опыте работы на нем можно создавать шикарные штучки – и в то же время удивительно универсальный. Почти каждая веб-страница включает в себя что-нибудь на JavaScript, и эти строки можно изучить, просматривая ее исходный код в браузере. Правда, чтобы найти нужный пункт, вам придется полазить в паре меню: браузеры усложняют поиск, хотя этого не должно быть. С помощью JavaScript поддерживаются многие эффекты веб-страниц, включая средства Google Docs и аналогичных программ из других источников. JavaScript также служит языком для API, на таких веб-сервисах, как Twitter, Facebook, Amazon и так далее.
Впрочем, у JavaScript есть и недостатки. Некоторые элементы языка неудобны, и порой проявляется неожиданное поведения. Браузерные интерфейсы не так стандартизированы, как хотелось бы, поэтому в разных браузерах программы не всегда ведут себя одинаково. Но на уровне, интересном для нас, это не проблема, и даже для профессиональных программистов ситуация улучшается.
Программы на JavaScript обычно запускаются как часть веб-страницы, хотя все чаще их можно выполнять вне браузера. Если вы используете JavaScript с браузером в качестве хоста, необходимо немного изучить HTML (Hypertext Markup Language) – язык для описания макета веб-страниц. (Мы мельком рассмотрим его в главе 10.) В общем, есть незначительные сложности, но все же стоит постараться и немного изучить JavaScript.
Другой наш язык – Python. Он отлично подходит для повседневной разработки программ в громадном диапазоне областей применения. За последние несколько лет Python стал стандартным языком для вводных занятий по программированию, а также для курсов по аналитике данных и машинному обучению. Хотя прежде вам пришлось бы работать с ним на вашем компьютере, сейчас появились веб-сайты, позволяющие запускать программы на Python как веб-сервис. Поэтому не нужно что-либо скачивать или изучать, как пользоваться интерфейсом командной строки. Если бы я преподавал курс программирования для людей, которые изучают свой первый ЯП, то выбрал бы именно Python.
Если вы разберетесь в приведенном здесь материале и немного поэкспериментируете, то сможете научиться программировать – по крайней мере, на базовом уровне, – а такой навык стоит того, чтобы им овладеть. Приобретенные вами знания в дальнейшем облегчат изучение других языков. Если вы хотите копнуть глубже или узнать еще чье-либо мнение, найдите в интернете учебные пособия по JavaScript или Python. Вы получите длинный список полезных сайтов, включая Codecademy, Khan Academy и W3Schools, которые обучают программированию полнейших новичков.
Несмотря на все вышесказанное, ничего страшного, если вы пролистаете эту главу, не обращая внимания на подробности синтаксиса. Для понимания других тем они не важны.

7.1. Принципы языков программирования

Языки программирования разделяют определенные базовые принципы, потому что все они представляют собой описания вычислений в виде последовательности шагов. В каждом ЯП есть методы для того, чтобы считывать входные данные, выполнять арифметические операции, хранить и извлекать промежуточные значения в ходе расчетов, решать, как продолжить процесс на основе предыдущих вычислений, отображать промежуточные результаты во время работы и сохранить итоговые по ее окончании.
ЯП имеют синтаксис — правила, которые определяют, что грамматически допустимо, а что нет. Языки программирования придирчивы к грамматике: вы должны всё писать верно, иначе последует жалоба. Кроме того, любой ЯП обладает семантикой, то есть четко определенным значением для всего, что вы можете сказать на конкретном языке.
Теоретически в отношении каждой программы можно однозначно определить, корректна ли она с точки зрения синтактиса, и если да, то какой в нее вложен смысл. К сожалению, этого идеала не всегда удается достичь. Как в любом документе на естественном языке, в программировании все обычно определяется словами – но их определения бывают двусмысленными и могут допускать разную интерпретацию. Кроме того, разработчики ошибаются, а языки со временем развиваются. Соответственно, реализации JavaScript отличаются в разных браузерах и даже в различных версиях одного и того же. Аналогично существует две версии Python, в основном совместимые, но их несхожесть все-таки раздражает. К счастью, вторая версия выходит из употребления: ее заменит Python 3, и эта проблема исчезнет.
Большинство ЯП имеют три компонента. Первый – это сам язык: команды для компьютера, велящие ему выполнить арифметическую операцию, проверить, соблюдаются ли условия, и повторить вычисления. Второй – библиотеки кода, написанные другие людьми, которые вы можете использовать в своей программе. Это уже готовые модули, и вам не нужно их заново составлять. Типичные их примеры – математические функции, календарные расчеты, функции поиска и действий с текстом. Третий компонент – доступ к среде, в которой работает программа. Так, программа на JavaScript, запущенная в браузере, может получать входные данные от пользователя, реагировать на события (нажатие кнопки, ввод текста в форму), а также побуждать браузер отобразить иной контент или перейти на другую страницу. Любой программе на Python предоставляется доступ к файловой системе на компьютере, где она запущена, однако это запрещено программам на JavaScript, работающим в браузере.

7.2. Первая программа на JavaScript

Я начну с языка JavaScript, затем мы перейдем к Python. После изучения JavaScript вам будет легче читать раздел про Python, хотя вы можете пойти в обратном порядке. Как правило, если вы разобрались в одном языке, освоить другие становится легче: вы уже понимаете принципы работы, нужно только выучить синтаксис.
Первая программа на JavaScript максимально короткая: она просто выводит диалоговое окно со словами Hello, world («Привет, мир») при загрузке веб-страницы. Вот полная страница в HTML – с этой разметкой мы еще познакомимся, когда будем говорить о Всемирной паутине в главе 10. Сейчас мы сосредоточимся на одной строчке JavaScript, которая появляется между <script> и </ script> (выделена жирным шрифтом).

 

 

Если вы поместите эти семь строчек в текстовый файл, назовете его hello.html и загрузите в свой браузер, то увидите результсат, показанный на рис. 7.1.
Изображения взяты из Firefox, Chrome, Edge и Safari на macOS. Как видите, разные браузеры могут вести себя по-своему. Safari отобразил «закрыть», но не в виде кнопки, а вот Edge почти идентичен Chrome, потому что основан на одной из его реализаций.
Функция alert входит в библиотеку JavaScript по взаимодействию с браузером. Она открывает диалоговое окно, которое отображает текст, написанный в скобках, и ждет, когда пользователь нажмет «ОК» или «Закрыть».

 

Рис. 7.1. Firefox, Chrome, Edge, Safari на macOS

 

Кстати, когда вы пишете собственную программу на JavaScript, используйте стандартный символ двойной кавычки (на английской раскладке), который выглядит как", а не так называемые «книжные кавычки» из привычных вам текстов. Это простой пример синтаксического правила. Кроме того, создавая HTML-файлы, не применяйте текстовые редакторы вроде Word – работайте в таких приложениях, как Блокнот или TextEdit, и проверяйте, что они сохраняют файлы в виде обычного текста (то есть простого ASCII без форматирования информации), даже если у файла расширение. html.
Когда этот пример заработает, вы сможете добавить в него некоторые интересные вычисления. Далее я не буду показывать код разметки HTML – только JavaScript между <script> и </script>.

7.3. Вторая программа на JavaScript

Вторая программа на JavaScript будет запрашивать у пользователя имя и выводить персонализированное приветствие:

 

 

В этой программе есть новые конструкции и идеи. Во-первых, слово var вводит (или объявляет) некую переменную — место в оперативной памяти, где программа может хранить значение во время работы. «Переменной» она называется потому, что ее значение способно меняться в ходе вычислений. Объявление переменной в языке высокого уровня аналогично присвоению имени ячейке памяти, что мы делали на ассемблерном языке в компьютере-игрушке. Образно говоря, такие объявления определяют действующих лиц, список персонажей в пьесе. Я назвал переменную username, то есть «имя пользователя», что указывает на ее роль в этой программе.
Во-вторых, программа задействует одну из библиотек JavaScript, где определена функция prompt, которая похожа на alert, но ее всплывающее диалоговое окно будет запрашивать у пользователя ввод. Любой текст, напечатанный им, будет доступен программе как значение, вычисленное функцией prompt. Оно присваивается переменной username в строчке:

 

username = prompt("Как вас зовут?");

 

Знак равенства «=» означает «выполнить операцию на правой стороне и сохранить результат в переменной, стоящей слева». Похоже на сохранение значения накопителя в памяти компьютера-игрушки. То, как здесь интерпретируется знак равенства, дает нам повод поговорить о семантике. Эта операция называется присвоением, причем «=» здесь означает не равенство, а копирование значения. Большинство языков программирования для присвоения использует знак равенства, пусть даже люди путают его с математическим равенством.
В последней инструкции, alert, используется знак плюс +:

 

alert("Привет, " + username);

 

Он соединяет слово «Привет» (а также запятую и пробел) и имя, которое ввел пользователь. Знак + тоже может
сбить с толку, потому что в этом контексте он означает не сложение чисел, а объединение (конкатенацию) двух последовательностей текстовых символов.
Когда вы запускаете программу, prompt выводит диалоговое окно, где вы можете напечатать текст, как показано на рис. 7.2 (в Firefox).

 

Рис. 7.2. Диалоговое окно, ожидающее ввода

 

Если вы введете «Джо» и нажмете ОК, то появится окно сообщения (см. рис. 7.3.)

 

Рис. 7.3. Появление кнопки ОК в диалоговом окне

 

Довольно просто будет расширить эту программу и создать отдельный ввод для имени и фамилии. В целом есть множество вариантов решений, с которыми можно попрактиковаться. Обратите внимание: если вы наберете «Меня зовут Джо», то в итоговом окошке появится «Привет, Меня зовут Джо». Если вы хотите, чтобы компьютер вел себя умнее, то запрограммируйте его сами.

7.4. Циклы и условия

На рис. 5.6 приводилась версия программы на JavaScript, которая суммирует последовательность цифр. На рис. 7.4 я повторил тот код, чтобы вам не пришлось перелистывать назад.

 

Рис. 7.4. Программа на JavaScript для сложения чисел

 

Напомню, что программа считывает числа, пока не будет введен нуль, а затем выводит сумму. Выше мы уже рассмотрели некоторые элементы языка, представленные в этом коде, – объявление, присвоение, а также функцию prompt. В первой строчке объявляются две переменные с именами num и sum, которые будут использоваться в программе. Вторая инструкция задает sum значение О, а третья присваивает num значение, которое пользователь печатает в диалоговом окне.
Затем появляется важный компонент – цикл while, в который входят строчки с 4 по 7. Компьютеры как устройства прекрасно умеют раз за разом выполнять последовательности инструкций, и проблема только в том, как выразить это повторение на ЯП. В языке для Игрушки мы ввели инструкцию GOTO, которая задает переход к другому месту в программе, а не к следующей команде по порядку, и инструкцию IFZERO, выполняющую переход, только если значение в накопителе равно нулю.
Эти концепции появляются в большинстве высокоуровневых языков в командах вида «цикл while», которые обеспечивают более упорядоченный и рациональный метод повторения последовательности операций. Оператор while проверяет условие (прописанное в круглых скобках) и, если оно истинно, выполняет по порядку все выражения между фигурными скобками Затем он возвращается к началу и снова проверяет условие. Этот цикл будет продолжаться, пока условие истинно. Когда оно становится ложным, программа выполняет то, что следует за закрывающей фигурной скобкой цикла.
Такая методика почти точно соответствует IFZERO и GOTO в программе для компьютера-игрушки, описанной в главе 3. Разница только в том, что с «цикл while» нам не нужно придумывать метки, а проверяемым условием может служить любое выражение, которое определяется как истинное или ложное. В данном случае проверяется, не записан ли в переменную num символ 0. Оператор! = означает «не равно»; он унаследован от языка С, как и сама инструкция while.
Сейчас я не уделял внимания типу данных, которые обрабатывают программы из примеров, но в целом компьютеры «внутри себя» четко разделяют числа вроде 123 и произвольный текст, такой как Hello. Одни языки требуют, чтобы программисты тщательно прописывали это различие, а другие пытаются угадать, что имелось в виду. JavaScript ближе ко второй позиции, но иногда необходимо уточнить тип данных, с которыми вы работаете, и то, как интерпретировать значения.
Итак, функция prompt возвращает символы (текст), и затем проверяется, нет ли там буквенной константы О, что задается путем помещения 0 в одинарные кавычки. Без них он воспринимался бы как число.
Функция parselnt преобразует текст во внутреннюю форму, пригодную для операций целочисленной арифметики. Другими словами, эти входные данные обрабатываются как целое число (например, 123), а не как три символа, случайно оказавшиеся десятичными цифрами. Если мы не используем parselnt, то данные, возвращенные функцией prompt, будут интерпретироваться как текст, и тогда оператор + добавит их в конец предыдущего текста. Результатом стала бы конкатенация всех цифр, которые ввел пользователь, что, пожалуй, занимательно, но не совсем то, что нам нужно. В следующем примере, показанном на рис. 7.5, выполняется немного другая работа: поиск наибольшего числа из всех введенных. Это повод представить вам еще одну команду потока управления – if-else, которая встречается в той или иной форме во всех высокоуровневых языках, играя роль способа принятия решения. По сути, это универсальный вариант IFZERO. Версия if-else в JavaScript такая же, как и в С.
Оператор if-else может иметь две формы. У показанного здесь нет части else: если условие в круглых скобках истинно, то выполняются команды, заключенные в { }. И в любом случае далее прогоняются инструкции, которые идут после закрывающей фигурной скобки. Более общая форма оператора содержит элемент else для последовательности команд, которые выполняются, если условие ложное. Далее, независимо от истинности условия, прогоняется инструкция, следующая за if-else.
Возможно, вы заметили, что в программах из примеров используется отступ для выделения структуры. Так, команды, зависящие от while и if, имеют отступ. Данная практика полезна, так как она позволяет с первого взгляда увидеть, насколько широка «зона влияния» операторов вроде while и if, которые управляют другими инструкциями.
Эту программу легко протестировать, запустив ее с веб-страницы, но профессионалы проверят ее заранее. Они будут моделировать поведение кода, мысленно проходя по инструкциям программы по одной за раз, чтобы сымитировать действия компьютера.

 

Рис. 7.5. Отыскание наибольшего числа из последовательности

 

Например, попробуйте прогнать в голове последовательности «1, 2, 0» и «2, 1, 0». Можете даже начать с последовательности «О», а затем «1, 0», дабы убедиться, что в простейших случаях все выполняется правильно. Это хорошая практика, помогающая удостовериться, что вы понимаете, как работает программа. Если вы так поступите, то убедитесь, что код дает верный результат для любой последовательности вводимых значений.
Или все-таки нет? Программа отлично работает, если вводится хотя бы одно положительное число. Но что, если все они окажутся отрицательными? Если вы попробуете указать такие значения, то программа всегда будет сообщать, что наибольшее число – это ноль.
Задумайтесь на мгновение почему. Программа отслеживает самое большое значение, которое на данный момент записано в переменной шах (прямо как с поиском самого высокого человека в комнате). Переменная должна иметь некоторое начальное значение до того, как мы начнем сравнивать с ней последующие числа, поэтому, перед тем как пользователь начинает печатать, программа задает значение, равное нулю. Все работает хорошо, если хотя бы одно входное значение больше нуля, как в случае с ростом людей. Но если пользователь задает только отрицательные числа, то программа не выводит самое большое из них. Она отображает первоначальное значение max, которое никогда не обновляется.
Эту ошибку легко устранить. Я покажу одно решение в конце обсуждения JavaScript, но вам тоже будет полезно подумать, как все отладить.
Данный пример также показывает важность тестирования. Для него требуется нечто большее, чем просто ввод случайных значений в программу. Хорошие тестировщики тщательно поразмыслят, что может пойти не так, включая странные или недопустимые входные данные, «пограничные» или «предельные» случаи – например, отсутствие данных или деление на ноль. Они не упустят и вероятность того, что будут введены только отрицательные числа. Но проблема в том, что по мере разрастания программы станет намного труднее продумывать все тестовые случаи, особенно если нужно учитывать участие людей, которые склонны задавать случайные значения, причем неопределенное количество раз и безо всякого порядка. Идеального решения не существует, но не помешает тщательно проработать и реализовать программу, а также с самого начала включить в нее проверки согласованности и работоспособности. Тогда, если что-то пойдет не так, программа наверняка обнаружит это сама и на ранней стадии.

7.5. Библиотеки и интерфейсы JavaScript

JavaScript играет важную роль как механизм расширения для сложных веб-приложений. Хороший пример – Google Maps. Язык предоставляет библиотеки и API, поэтому операции с картами могут задаваться программами JavaScript, а не только щелчками мыши. Таким образом, кто угодно может написать на JavaScript код для отображения информации на карте от Google. API прост в использовании: например, код на рис. 7.6 (если добавить несколько строчек HTML и ключ авторизации от Google) показывает место на карте (рис. 7.7), где, возможно, какой-нибудь читатель однажды поживет несколько лет.
Как мы увидим в главе 11, в интернете отмечается тенденция все больше использовать JavaScript, в том числе с программируемыми интерфейсами, как у Google Карт. Один из недостатков здесь – сложность защиты интеллектуальной собственности. Ведь если вы используете JavaScript, то обязаны раскрывать исходный код. Любой желающий может заглянуть в браузере в ИК страницы.

 

Рис. 7.6. JavaScript-код для использования Google Maps

 

Рис. 7.7. В такой перспективе выглядит скромно, да?

 

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

7.6. Как работает JavaScript

Вспомните описание компиляторов, ассемблеров и машинных команд в главе 5. Программа на JavaScript преобразуется в исполняемую форму аналогичным образом, однако подробности существенно отличаются. Когда браузер встречает код JavaScript на веб-странице (например, увидев тег <script>), он передает текст программы компилятору JavaScript. Тот проверяет ее на наличие ошибок и транслирует в инструкции на ассемблерном языке для воображаемой машины, аналогичной нашей Игрушке, но с более обширным набором инструкций, – то есть виртуальной машины, описанной в предыдущей главе. Затем она запускает симулятор, опять же подобный Игрушке, для выполнения любых действий, которые заданы в программе на JavaScript. Симулятор и браузер тесно взаимодействуют: например, когда пользователь нажимает кнопку, браузер уведомляет об этом действии моделирующую программу. Когда симулятор хочет, например, чтобы появилось диалоговое окно, он просит об этом браузер, и тот вызывает функции alert или prompt.
Это всё, что я хотел рассказать о JavaScript. Но если вам захотелось разобраться подробнее, есть хорошие книги и онлайн-руководства, где вы «на лету» научитесь редактировать код JavaScript и сразу видеть результаты66. Программирование порой выводит из себя, но иногда приносит огромное удовольствие, и вы даже можете прилично зарабатывать им на жизнь. Программистом способен стать каждый, но вам весьма пригодятся скрупулезность и умение пристально изучать мелкие элементы, а затем снова окидывать взглядом всю картину. Также помогает небольшая одержимость правильным воплощением деталей, поскольку программы не заработают (или будут работать плохо), если вы невнимательны. Как и в большинстве других областей, здесь огромная разница между любителями и настоящими профессионалами.
Вот один из ответов на вопрос о программировании, заданный пару страниц назад:

 

 

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

7.7. Первая программа на Python

Далее я повторю кое-какой материал из первой части главы, но уже для языка Python, уделяя особое внимание его отличиям от JavaScript. Благодаря одному из основных изменений, произошедших несколько лет назад, теперь легко запускать программы на Python из браузера. Значит, как и в случае с JavaScript, вам не нужно ничего загружать на вашу машину. Всё так же действуют ограничения по доступу и ресурсам – вы ведь буквально запускаете свою программу на чужом компьютере, – но на первых порах вам хватит того, что есть.
Если у вас локально установлен Python67, можете запустить его из командной строки с помощью терминала в macOS или Windows. По традиции первая программа печатает «Hello, world», и взаимодействие выглядит следующим образом:

 

 

Всё, что набираете вы, отображается жирным курсивом, текст, напечатанный компьютером, – моноширинным шрифтом, а»> – приглашение ввода самого языка Python.
Если у вас не инсталлирован Python или вы хотите попробовать онлайн-альтернативу, существует множество сервисов, которые позволяют запускать его из веб-браузера. Один из самых простых – Colab от Google68. Он обеспечивает удобный доступ к различным инструментам машинного обучения. В подробности этого мы здесь вдаваться не будем, но Colab также хорош для начала работы с Python. Если вы зайдете на веб-сайт Colab, выберете File, затем New notebook, введете программу в поле «+ Code» и, если пожелаете, текст в поле «+ Text», то перед вами должна появиться страница, показанная на рис. 7.8. На ней изображена ситуация непосредственно перед запуском первой программы: строка из текста, который объясняет, что представляет собой пример, а затем сам код.

 

Рис. 7.8. Colab перед запуском «Hello, world»

 

Чтобы скомпилировать и запустить программу, щелкните по значку треугольника (появляется при наведении). Результат показан на рис. 7.9.

 

Рис. 7.9. Colab после запуска Hello, world

 

Текстовая область используется для документации любого вида, а кода вы можете добавлять сколько захотите. В ходе разработки системы вы также вправе включить дополнительные разделы для текста и кода. Colab – это облачная версия широко используемого интерактивного инструмента Jupyter notebook69, компьютерного аналога физической записной книжки, куда вы заносите ваши идеи, разъяснения, отчеты об экспериментах, код и данные. Все сохраняется на одной веб-странице, которую затем можно редактировать, обновлять, выполнять и делиться с другими. Более подробную информацию ищите по адресу jupyter.org.

7.8. Вторая программа на Python

Мы уже знакомы с программой, которая складывает последовательность чисел и печатает итоговую сумму, – она описана в главе 5. Версия, показанная на рис. 7.10, выводит вместе с суммой сообщение, но в остальном они идентичны. (Эта программа не будет работать, если вы просто скопируете ее и вставите в Python, потому что вызов функции input интерпретируется сразу. Вы должны создать отдельный файл, например, addup.py, и затем запустить Python из него.)

 

Рис. 7.10. Программа на Python для сложения чисел

 

Давайте добавим это в наш блокнот Colab. На рис. 7.11 показаны код и статус программы сразу после начала выполнения. Голубой прямоугольник – это поле для ввода, эквивалент диалогового окна prompt, которое мы использовали в JavaScript.

 

Рис. 7.11. Colab перед запуском Addup

 

На рис. 7.12 показан результат вычислений после того, как я напечатал числа 1, 2, 3, 4, а затем 0, который завершил цикл. Данная версия программы показывает текстовое сообщение, в котором прописывается вывод, но оно не появляется перед каждым вводом. Добавьте такую функцию сами – это простое и полезное упражнение.

 

Рис. 7.12. Colab после запуска Addup

 

В следующем примере приведена программа (рис. 7.13), которая вычисляет максимальное значение в последовательности чисел.

 

Рис. 7.13. Colab перед запуском Мах

 

На рис. 7.14 показан результат после ввода последовательности чисел. Обратите внимание, что программа выдает правильный ответ, даже если все числа отрицательные.

 

Рис. 7.14. Colab после запуска Мах

 

Вы можете внести одно незначительное изменение: вместо того чтобы использовать только целые числа, перепишите программу так, чтобы обрабатывались и числа с плавающей запятой, то есть такие, что потенциально содержат дробную часть (например, число 3,14). Для этого потребуется всего одна правка – поставить float вместо int в строчках, где текст ввода преобразуется в числовые внутренние формы.

7.9. Библиотеки и интерфейсы Python

Одна из самых сильных сторон Python – огромная коллекция библиотек, доступных программистам. Назовите какую угодно область применения приложений – вероятно, для нее найдется библиотека Python, которая упростит написание программы.
Я проиллюстрирую это одним кратким примером – библиотекой matplotlib для рисования графиков. Предположим, мы хотим воспроизвести то, что показано на рис. 4.1 (как время выполнения задачи возрастает пропорционально объему данных).
Первоначально я создал этот рисунок в Excel, но его можно легко выполнить и в Python, опять же с помощью нашего блокнота Colab.

 

Рис. 7.15. Расчет графика классов сложности

 

В коде на рис. 7.15 представлено несколько новых функциональных средств. Два оператора import используются для доступа к библиотекам кода Python – математической и построения графиков. Последняя имеет длинное имя, поэтому ей обычно присваивается короткий псевдоним pit. Значения, которые надлежит вычислить и нанести на график, сохраняются в четырех изначально пустых списках, заданных строчкой:

 

 

Затем инструкции добавляют новые значения в списки, выполняются циклично от 1 до 20 включительно и на каждом шаге устанавливают для переменной п текущее значение.
В конце цикла все списки (теперь включающие по 20 элементов) подготавливаются для построения графика путем вызова функции plot. Затем она создает рисунок и добавляет метки к его легенде. Но есть одно исключение: из списка квадратичных значений (quadratic) для построения графика берутся только первые десять элементов, ведь квадраты п увеличиваются настолько быстро, что иначе остальные линии на рисунке просто сольются. Записью [0:10] мы выбираем срез списка, содержащий первые десять элементов, которые пронумерованы от 0 до 9.
Функция legend задает легенду с метками для каждой кривой, a show генерирует график, показанный на рисунке 7.16.
В matplotlib есть еще огромное количество функций, так что вам стоит изучить их и посмотреть, сколь многое вы можете сделать без особых усилий.
Большинство программ, рассмотренных в примерах, работали с числами. Возможно, у вас сложилось впечатление, что программирование сводится только к таким расчетам. Но, конечно, это неправда: в жизни нас окружает множество интересных приложений, не связанных с числами.

 

Рис. 7.16. Рост log N, N, N log N и N2

 

Библиотеки Python также позволяют легко экспериментировать с текстовыми приложениями. На рис. 7.17 используется библиотека Python requests, с помощью которой мы получаем доступ к копии романа «Гордость и предубеждение» с сайта Gutenberg.org и отображаем на экране знаменитое вступительное предложение. В начале книги есть изрядный объем стандартного текста, который нужно пропустить. Функция find находит в тексте начальную позицию отрывка, где впервые появляется заданная строка символов, и мы можем использовать ее, чтобы отыскать фрагмент от начала и до конца.
Часть программы

 

pandp = pandp[start:]

 

заменяет исходный pandp подстрокой, которая начинается с позиции start и доходит до конца строки.
Затем мы снова используем find, чтобы найти первую точку, которая находится в конце первого предложения, а затем напечатать подстроку, начинающуюся с нулевой позиции. Почему end+1? В переменной end содержится положение «.», поэтому нам нужно увеличить ее на единицу, чтобы включить саму точку.

 

Рис. 7.17. Доступ к интернет-данным с помощью Python

 

В последних примерах я изложил много материала без подробных объяснений, чтобы кратко показать некоторые основные идеи. С таким большим объемом кода вам легко провести простые эксперименты. Например, вывести другие значения функции, такие как квадратный корень (sqrt) или N3 или даже 2N. Для этого потребуется изменить диапазон данных. Или же попробуйте изучить средства matplotlib, которые способны выполнять гораздо больше действий, чем показано здесь. Можно загрузить больше отрывков «Гордости и предубеждения» или других текстов и применить к ним пакеты Python для обработки естественного языка (например, NLTK или spaCy).
По моему опыту, эксперименты с уже готовым кодом – это эффективный способ лучше разобраться в программировании. А чтобы держать все результаты ваших опытов в одном месте, хорошо подойдут «записные книжки» вроде тех, что доступны на Colab.

7.10. Как работает Python

Вспомните, как в главе 5 мы обсуждали компиляторы, ассемблеры и машинные инструкции, а несколько страниц назад я объяснял принципы работы JavaScript. Программа на Python преобразуется в исполняемую форму аналогичным способом, хотя детали существенно отличаются. Когда вы запускаете Python (неважно, напрямую с помощью команды python в среде командной строки или нажав что-либо на веб-странице), текст вашей программы передается его компилятору.
Тот проверяет программу на наличие ошибок и компилирует ее в инструкции на ассемблерном языке для условной машины, аналогичной нашей Игрушке, хотя и с более богатым набором инструкций. Описание виртуальных машин приведено в главе 6. Если есть инструкции import, то также включается код из вызываемых ими библиотек. Компилятор затем запускает ВМ для выполнения всех действий, которые должна совершить программа на Python. Взаимодействуя со средой, виртуальная машина проводит такие операции, как считывание данных с клавиатуры или из интернета и вывод результатов на экран.
Если вы запускаете Python через командную строку, то он пригодится даже в качестве мощного калькулятора. Вы можете печатать по одной инструкции языка за раз, и каждая из них будет немедленно компилироваться и выполняться. Это позволяет легко экспериментировать с языком и выяснять, на что способны основные функции. Так даже проще, чем разбираться с Python в чем-то вроде блокнота Jupyter или Colab.

7.11. Краткие выводы

В последние несколько лет стало модно поощрять всех обучаться программированию, причем в процесс активно включились известные и влиятельные люди.
Следует ли вводить программирование как обязательный предмет в начальной или старшей школе? А в университетах (о чем постоянно спорят у меня на работе)?
Я считаю, что всем людям полезно знать, как программировать. Это поможет им лучше понимать, что делают компьютеры и каким образом. Программирование бывает приятным и полезным способом провести время. Шаблоны мышления и подходы к решению проблем, используемые при написании кода, отлично пригодятся во многих других сферах жизни. И, безусловно, знание программирования открывает перед вами двери к хорошей карьере и достойному заработку.
Но все-таки что это занятие подходит не каждому, и я не думаю, что все должны изучать программирование, в отличие от обязательных навыков вроде чтения, письма и арифметики. Лучше сделать эту идею привлекательной, добиться, чтобы людям было легко начать, предоставить им обширные возможности, устранить как можно больше препятствий, а затем пусть все идет своим чередом.
Более того, информатика, часто упоминаемая в таких дискуссиях, включает в себя не только программирование, хотя оно и занимает в ней важное место. В университетский курс информатики также входят теоретическое и практическое изучение алгоритмов и структур данных, которые мы рассмотрели в главе 4. В том числе изучаются архитектура, языки, операционные системы, сети и приложения из огромного диапазона областей, где информатика объединяет усилия с другими дисциплинами. Опять же, это превосходно для отдельных людей, и многие идеи оттуда находят широкое применение. Но требовать, чтобы все подряд официально изучали информатику, – это перебор.
Краткое заключение по программному обеспечению
В последних четырех главах мы рассмотрели солидный объем материала. Вот краткое изложение наиболее важных моментов.
Алгоритмы. Алгоритм – это последовательность точно и однозначно заданных шагов, которые выполняют конкретную задачу, после чего происходит остановка. Описание расчетов не затрагивает детали их реализации. Шаги основаны на четко определенных операциях, элементарных или примитивных. Есть множество алгоритмов, но мы рассмотрели самые основные, такие как поиск и сортировка.
Сложность. Сложность алгоритма – это абстрактное описание того, как много работы он выполняет. Измеряется она в разрезе базовых операций – например, проверки элементов данных или сравнения оных, – и выражается через их количество на определенный объем данных. Это приводит к появлению иерархии сложностей, которая в нашем случае варьируется от логарифмической (удвоение количества элементов добавляет только одну операцию) и линейной (удвоение количества элементов удваивает количество операций) до экспоненциальной (добавление одного элемента удваивает количество операций).
Программирование. Если алгоритмы абстрактны, то программа – это конкретное описание всех шагов, которые побуждают реальный компьютер выполнять реальную задачу. Программа должна справляться с ограничениями памяти и времени, конечностью размера и точности чисел, своенравными пользователями или злоумышленниками и постоянными изменениями среды.
Языки программирования. ЯП представляет собой систему обозначений, с помощью которой все эти шаги записываются в удобной для людей форме, которая затем переводится в двоичное представление для конечного использования ЭВМ. Преобразование может выполняться несколькими способами, но чаще всего компилятор, иногда с поддержкой ассемблера, транслирует программу (написанную, например, на языке С) в бинарный вид для запуска на реальном компьютере. Поскольку каждый тип процессора имеет различный набор и представление инструкций, им нужны разные компиляторы, однако некоторые части последних одинаковы для разных ЦПУ. Интерпретатор или виртуальная машина – это программа, имитирующая настоящий или условный компьютер, для которого можно компилировать и запускать код. Обычно так работают программы на JavaScript и Python.
Библиотеки. Чтобы создать программу для запуска на реальном компьютере, требуется расписать множество замысловатых мелочей даже для обычных операций. Библиотеки и связанные с ними механизмы предоставляют компоненты, которые программисты используют при создании собственных программ, благодаря чему новая работа опирается на уже готовый фундамент. В настоящее время при составлении программ в равной мере применяется как «склеивание» существующих компонентов, так и написание оригинального кода. К компонентам библиотеки могут относиться как функции (например, те, что мы видели в JavaScript и Python), так и большие системы вроде Google Maps и других веб-сервисов. Библиотеки бывают как с открытым исходным кодом (любой программист может его читать, понимать и улучшать), так и с закрытым, проприетарным. Впрочем, фактически все они созданы программистами, которые написали подробные инструкции на каком-либо ЯП, либо из упомянутых выше, либо на каком-то еще.
Интерфейсы. Прикладной программный интерфейс, или API, – это контракт между двумя сторонами: ПО, оказывающим некоторую услугу, и ПО, использующим ее. Через API библиотеки и компоненты предоставляют свои сервисы. Благодаря интерфейсам вызова ОС аппаратное обеспечение отображается более стандартно и легче поддается программированию.
Абстракция и виртуализация. Абстракция – это фундаментальная концепция в вычислительной технике, которую можно встретить на всех уровнях, от оборудования до крупных программных систем. Это особенно актуально при разработке и внедрении ПО, поскольку оно структурно отделяет то, как задача описана во фрагментах кода, от того, как она реализуется. Программное обеспечение способно скрывать детали реализации или притворяться чем-то другим. В числе примеров здесь виртуальная память, виртуальные машины-интерпретаторы и даже облачные вычисления.
Ошибки (баги). Компьютеры неумолимы, и программирование требует от разработчиков (неидеальных по природе своей) постоянного высокого уровня точности в работе. Неудивительно, что все крупные программы забагованы, из-за чего действуют не совсем так, как задумывалось. Одни ошибки просто доставляют неудобство, они больше похожи на недочеты в дизайне, чем на реальные дефекты. («Это не баг, а фича» – распространенная поговорка среди программистов.) Другие проявляются только в таких редких и необычных ситуациях, что их невозможно даже воспроизвести, не говоря уже об исправлении. Лишь немногие баги действительно серьезны и способны привести к тяжелым последствиям, когда под угрозой окажутся безопасность, защищенность и даже жизни людей. Сегодня подверженность воздействиям становится более серьезной проблемой для вычислительных устройств, особенно когда растет число критически важных систем, зависящих от ПО. Модель «Хочешь – бери, хочешь – нет, но без гарантии», на которой основано использование персональных компьютеров, скорее всего, будет заменена более разумными гарантиями на продукт и принципами защиты потребителей, уже действующими в мире аппаратного обеспечения.
Как мы понимаем из опыта, по мере того как в программах все чаще используются проверенные компоненты, а известные ошибки устраняются, код в принципе должен содержать все меньше дефектов. Однако на пути этих достижений стоят неизбежные проблемы, возникающие из-за постоянных изменений, связанных с тем, что компьютеры и языки развиваются, к системам предъявляют новые требования, а нужды маркетинга и желания потребителей непрерывно создают потребность в дополнительных функциях. Это приводит к появлению все более масштабных программ. К сожалению, баги никогда нас не покинут.
Назад: 6. Программные системы
Дальше: Часть III Коммуникации