Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Программирование на языке Python. Учебное пособие.pdf
X
- •ПРЕДИСЛОВИЕ
- •I. ВВЕДЕНИЕ В ПРОГРАММИРОВАНИЕ
- •1. Начало работы
- •2. Основные понятия
- •Ввод и вывод данных
- •Логические операторы
- •Условные инструкции
- •Инструкции
- •Типы данных
- •Константы и переменные
- •Арифметические операторы
- •Операторы сравнения
- •3. Функции
- •Определение функций
- •Встроенные функции
- •Многократное использование функций
- •Типы параметров функции
- •Область видимости
- •Обработка исключений
- •Строки документации
- •4. Контейнеры
- •Методы
- •Списки
- •Кортежи
- •Словари
- •Контейнеры внутри контейнеров
- •5. Операции со строками
- •6. Циклы
- •Цикл for
- •Цикл while
- •Операторы break и continue
- •Функция Enumerate
- •Вложенные циклы
- •Настройка функции print()
- •7. Модули
- •8. Файлы
- •Запись в файлы
- •Использование конструкции with
- •Чтение из файлов
- •CSV-файлы
- •II. ВВЕДЕНИЕ В ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ (ООП)
- •9. Парадигмы программирования
- •Состояние
- •Процедурное программирование
- •Функциональное программирование
- •Объектно-ориентированное программирование
- •10. Базовые понятия ООП
- •Наследование
- •Полиморфизм
- •Абстракция
- •Инкапсуляция
- •Композиция
- •11. Дополнительные понятия ООП
- •Как работают переменные
- •Ключевое слово is
- •Константа None
- •Классы – это объекты
- •Переменные класса и переменные экземпляра класса
- •Приватные переменные
- •Методы переопределения
- •Функция super
- •Переопределение встроенных методов
- •12. Создание игр
- •Карты
- •Колода
- •Игрок
- •Игра
- •Игра «War»
- •13. Bash
- •Запуск Bash
- •Использование Bash
- •Относительные и абсолютные пути
- •Навигация
- •Флаги
- •Редактор vim
- •Команда touch
- •Просмотр файлов командой less
- •Пользователи
- •Разрешения
- •Программы Bash
- •Скрытые файлы
- •Переменные окружения
- •Переменная окружения $PATH
- •Вертикальная черта (пайп)
- •Команда cat
- •Последние команды
- •Быстрые перемещения
- •Экранирование (escaping)
- •Регулярные выражения в Python
- •15. Менеджеры пакетов
- •Вкладка «Завершение»
- •Функция wildcard (подстановочный знак)
- •Другие инструменты
- •14. Регулярные выражения
- •Настройка
- •Простое совпадение
- •Игнорирование регистра
- •Вывод только конкретных совпадений слов
- •Совпадение в начале и в конце
- •Поиск совпадений с несколькими символами
- •Повторение
- •Диапазон
- •16. Управление версиями
- •Репозитории
- •Помещение и извлечение данных
- •Пример помещения данных
- •Пример извлечения данных
- •Откат версий
- •Команда git diff
- •Другой запрос на включение
- •IV. ВВЕДЕНИЕ В ИНФОРМАТИКУ
- •17. Структуры данных и алгоритмы
- •Что такое алгоритмы и структуры данных?
- •Нотация Big-O
- •Оператор деления по модулю
- •Сортировка методом пузырька
- •Поисковый алгоритм
- •Рекурсия
- •Абстрактные типы данных
- •Узлы
- •Стеки
- •Связанные списки
- •Массивы
- •Бинарные деревья
- •Поиск в ширину и в глубину
- •Хэш-таблицы
- •ЗАКЛЮЧЕНИЕ
- •БИБЛИОГРАФИЧЕСКИЙ СПИСОК

Функциональное программирование
Функциональное программирование – еще одна популярная парадигма
программирования. Оно включает в себя написание функций, которые при одних и тех же входных данных всегда возвращают одни и те же выходные данные. В функциональном программировании программируют только с помощью
функций, не используя классы – особенность объектно-ориентированного программирования. В функциональном программировании много жаргона, и программист Мэри Роуз Кук дает ему следующее определение: “Функциональный
код характеризуется одним свойством: отсутствием побочных эффектов. Он не
полагается на данные вне текущей функции и не изменяет данные, существующие вне текущей функции”. Она подкрепляет свое определение примером
функции, имеющей побочные эффекты:
a = 0
def increment():
global a
a += 1
И примером функции, не имеющей побочных эффектов.
def increment(a):
return a + 1
Первая функция имеет побочные эффекты, поскольку она полагается на
данные за своими пределами и изменяет данные вне текущей функции путем
увеличения глобальной переменной. Вторая функция не имеет побочных эффектов, потому что она не полагается ни на какие данные за своими пределами,
и не изменяет эти данные.
В функциональном программировании программисты пишут функции таким
образом, чтобы устранить побочные эффекты – непреднамеренные последствия,
которые возникают, когда постоянно меняют состояние своей программы.
Объектно-ориентированное программирование
Парадигма объектно-ориентированного программирования (ОПП) вклю-
чает в себя написание программ, в которых определяются и создаются объекты,
взаимодействующие друг с другом. До сих пор вы оперировали такими объектами, как строки, целые числа и числа с плавающей запятой. Но также можно
81

определить свои собственные объекты с помощью классов. Классы – это схема, используемая для создания объектов. Можно думать о классе как об идее
объекта, например об апельсине. Апельсин – это объект. Плод весом от 200 до
300 грамм – это идея апельсина, то есть соответствующего класса.
Можно смоделировать апельсины в Python, определив класс, который затем использовать для создания объектов orange, определить класс, используя
ключевое слово class, за которым следует имя, которое присваивается классу.
Класс – это составная инструкция с заголовком и телом класса. Тело пишется
после заголовка. Телом могут быть как простые, так и составные операторы,
называемые методами. Методы похожи на функции, но они определены внутри
класса и могут быть вызваны только в объекте, созданном классом. В главе 3
приводились примеры, которые вызывали различные методы для строк вроде
"Hello".upper(). Вот пример того, как можно представить апельсин с помощью класса в Python:
class Orange:
print("Orange created!")
За ключевым словом class следует имя класса – в данном случае
Orange, потому что моделируются апельсины. По соглашению классы
в Python всегда начинаются с заглавной буквы и пишутся в стиле CamelCase
(с англ. – «ВерблюжийРегистр», также «ГорбатыйРегистр») – это означает, что
если имя класса состоит более чем из одного слова, слова не должны разделяться символом подчеркивания (как имя функции), вместо этого каждое слово
должно быть написано с заглавной буквы, как это – LikeThis.
После определения класса в теле класса присутствует простая инструкция
– print("Orange created!"). Этот код будет выполняться, когда бу-
дет создан объект orange. С помощью этого определения класса можно создать сколько угодно объектов Orange:
orange = Orange()
print(type (orange))
print(orange)
>> Orange created!
>> <class '__main__.Orange'>
>> <__main__.Orange object at 0x101a787b8>
82

При создании нового объекта Orange используется тот же синтаксис для
вызова функции – [classname](). Это называется созданием экземпляра объекта, что означает создание нового объекта. "Orange created!" печатается, как только создался экземпляр объекта Orange. При печати слова
type(orange)функция type сообщает, что объект Orange является экземпляром класса Orange, который только что был создан. При печати объекта
Orange Python сообщает, что это объект Orange, а затем указывает его ме-
стоположение в памяти. Когда печатается такой объект, расположение в памяти, напечатанное на компьютере, не будет таким же, как в примере, поскольку
местоположение объекта в памяти меняется при каждом запуске программы.
Заметим, что термины «объект» и «экземпляр» взаимозаменяемы.
Добавим метод в класс Orange. Методы определяются таким же синтаксисом, что и функции. Есть только два отличия: метод должен быть определен
как тело в классе и метод должен принимать, по крайней мере, один параметр
(кроме особых случаев). Можно произвольно назвать первый параметр метода,
но по соглашению, которое никогда не нарушалось, в методе он всегда называется self.
Причина, по которой каждый метод должен иметь первый параметр, заключается в том, что всякий раз, когда метод вызывается для объекта, Python
автоматически передает методу объект, который его вызвал. Эта концепция
существует в большинстве языков программирования, поддерживающих ООП,
однако Python делает передачу self в качестве параметра явной, в то время
как многие другие языки делают ее неявной. Python заставляет явно определять
self в каждом создаваемом методе, тогда как в других языках self просто
подразумевается, что он был передан объекту. Если определили метод и напечатали self, то видно, что это объект Orange, для которого вызывали метод:
class Orange:
print("Orange created!")
def print_orange(self):
print(self)
Orange().print_orange()
>> Orange created!
>> <__main__.Orange object at 0x101a787b8>
83

Параметр self полезен для определения и доступа к переменным, принадлежащим объекту Orange. Делается это для определения специального метода под названием __init__, который означает инициализацию. Когда создается экземпляр объекта, если определили метод с именем __init__, Python
автоматически вызывает метод __init__ при создании объекта. Внутри
__init__ можно указать переменные объекта Orange с синтаксисом
self.[variable_name] = [variable_value].
Пример:
class Orange:
print("Orange created!")
def __init__ (self):
self.color = "orange"
self.weight = 300
def print_orange(self):
print(self)
print(self.color)
print(self.weight)
orange = Orange()
orange.print_orange()
>> Orange created!
>> <__main__.Orange object at 0x10564dba8>
>> orange
>> 300
Используя __init__, теперь можно создавать апельсины, которые полу-
чают цвет и вес при инициализации, и использовать и изменять эти переменные
в любом из методов, как и обычные переменные. В Python любой метод, окруженный с обеих сторон двойными нижними подчеркивания, называется магическим методом (это означает, что он делает что-то особенное). Метод
print_orange был использован для иллюстрации примера, он не будет мето-
дом в нашем orange, поскольку продолжаем его моделировать.
Можно изменить определение нашего класса, чтобы программист, созда-
ющий объект (создание нового объекта называется созданием экземпляра
класса), мог передавать свои собственные переменные при создании нового
84

объекта orange вместо веса и цвета, которые были по умолчанию. Вот новое
определение класса:
class Orange:
def __init__ (self, weight, color, mold):
self.weight = weight
self.color = color
Теперь можно создавать более разнообразные объекты orange:
orange = Orange(300, 'orange')
Таким образом был создан 300-граммовый объект orange оранжевого
цвета. Теперь можно получить доступ к переменным объекта orange, используя точечную нотацию:
print(orange.weight)
>> 300
print(orange.color)
>> "orange"
Также можно изменить любой из параметров объекта orange:
orange.weight = 400
print(orange.weight)
>> 400
Моделируя апельсин, отметим, что апельсин – это нечто большее, чем просто его физические свойства, такие как цвет и вес. С апельсином тоже может
что-то происходить; нужно уметь моделировать и это. Что может произойти
с апельсином? Ну, во-первых, апельсин может гнить. Можно смоделировать
процесс гниения апельсина, добавив соответствующую переменную mold
в класс Orange и создав метод, который увеличивает переменную плесени при
ее вызове:
class Orange():
def __init__ (self):
self.weight = 200
self.color = 'orange'
self.mold = 0
85

def rot(self, days, temperature):
self.mold = days * (temperature * .1)
orange = Orange()
print(orange.mold)
orange.rot(10, 37)
print(orange.mold)
>> 0
>> 37.0
Определили метод, который принимает в качестве параметров количество
дней, прошедших с момента сбора апельсина, и среднюю температуру за это время. Из этой формулы можно увеличивать количество плесени в апельсине каждый раз, когда вызывается метод гниения rot (увеличение плесени отражает пе-
ременная экземпляра mold); и теперь апельсин обладает свойством гнить.
В ООП используются классы для моделирования объектов. Эти объекты
объединяют переменные (состояние) и методы (для изменения состояния)
в единое целое – объект. У классов есть специальный метод __init__, ко-
торый Python вызывает, когда объект создается с использованием синтаксиса [имя_класса](). Это пример одного из магических методов Python.
Первый аргумент любого метода по соглашению называется self и существует потому, что Python автоматически передает объект, вызвавший метод,
в метод.
Особо подчеркнем, что в классе можно определить несколько методов.
Это продемонстрировано на примере построения геометрической фигуры –
прямоугольника с помощью двух методов: 1) расчета площади и 2) изменения
размера.
class Rectangle():
def __init__ (self, w, l):
self.width = w
self.len = l
def area(self):
return self.width * self.len
def change_size(self, w, l):
self.width = w
self.len = l
86

rectangle = Rectangle(10, 20)
print(rectangle.area())
rectangle.change_size(20, 40)
print(rectangle.area())
>> 200
>> 800
Объекты Rectangle имеют две переменные экземпляра: len и width.
Метод area возвращает площадь объекта Rectangle, а метод change_size
изменяет переменные, присваивая им числа, которые передаются в качестве параметров.
У ООП имеются как преимущества, так и недостатки.
Преимущества.
• Парадигма ООП способствует повторному использованию кода и вслед-
ствие этого сокращает количество времени, необходимое на разработку и обслуживание кода.
• Проблемы разбиваются на множество фрагментов, благодаря чему код
становится легче поддерживать.
Недостатки.
• Создание программ требует больших усилий, поскольку их разработка
включает огромный объем планирования.
10. Базовые понятия ООП
В ООП есть четыре основных понятия, которые часто называют его четырьмя столпами: абстракция, инкапсуляция, наследование и полиморфизм.
Все они должны присутствовать в языке программирования, чтобы его можно
было считать объектно-ориентированным. Python является объектноориентированным языком. Не все языки программирования поддерживают
ООП, например, Haskell – это функциональный язык программирования, который не поддерживает ООП. Рассмотрим более подробно ООП, исследуя каждый из четырех упомянутых столпов.
87

Наследование
Наследование в программировании аналогично генетическому наследова-
нию. При генетическом наследовании можно унаследовать атрибуты от своих
родителей, например цвет глаз. Аналогично, когда создаете класс, он может
наследовать от другого класса (который называется родительским классом или
суперклассом), предоставляя новому созданному классу (класс, который
наследует, называется дочерним или подклассом) переменные и методы родительского класса. Смоделируйте геометрические фигуры, используя наследование. Определите класс для представления фигуры:
class Shape():
def __init__(self, w, l):
self.width = w
self.len = l
def print_size(self):
print("""{} на
{}""".format(self.width,self.len))
my_shape = Shape(20, 25)
my_shape.print_size()
>> 20 на 25
Этот класс позволяет создавать объекты фигур Shape с двумя параметра-
ми: шириной width и длиной len. Вдобавок объекты класса Shape имеют
метод print_size, выводящий эти параметры.
Теперь создайте дочерний класс Square, наследующийся от родительско-
го класса Shape. Наследование осуществляется передачей имени родительского класса в качестве параметра дочернему классу при его создании.
class Shape():
def __init__(self, w, l):
self.width = w
self.len = l
def print_size(self):
print("""{} на
{}""".format(self.width,self.len))
88

class Square(Shape):
pass
a_square = Square(20,20)
a_square.print_size()
>> 20 на 20
Так как класс Shape передан классу Square как параметр, то он наследует переменные и методы родительского класса Shape, а также может вызывать
метод print_size. Тело класса Square состоит только из оператора pass,
в ходе выполнения которого ничего не происходит, в связи с чем он может ис-
пользоваться в качестве заглушки в тех местах, где это синтаксически необходимо, например в инструкциях, где тело является обязательным, таких как def,
except и прочих. Иногда pass используют там, где код пока отсутствует, но
планируется, а также используют при отладке, разместив на строчке с ним точку остановки.
Благодаря наследованию можно создавать класс Square без необходимости писать еще какой-либо код (за исключением pass) в классе Square,
кроме того, что особенно важно, достигается существенное сокращение кода.
Дочерний класс абсолютно аналогичен любому другому классу, в нем
можно определять собственные методы и переменные, не затрагивая родительский класс.
class Shape():
def __init__(self, w, l):
self.width = w
self.len = l
def print_size(self):
print("""{} на
{}""".format(self.width,self.len))
class Square(Shape):
def area(self):
return self.width * self.len
a_square = Square(20, 20)
print(a_square.area())
>> 400
89

Наследуя метод от суперкласса, подкласс может переопределить его, то
есть определить новый метод с таким же именем, как у метода, который был
унаследован. Эта процедура называется переопределением метода.
class Shape():
def __init__(self, w, l):
self.width = w
self.len = l
def print_size(self):
print("""{} by {}""".format(self.width,self.len))
class Square(Shape):
def area(self):
return self.width * self.len
def print_size(self):
print("""Я {} на {}""".format(self.width,self.len))
a_square = Square(20, 20)
a_square.print_size()
>> Я 20 на 20
Новый метод print_size переопределяет родительский метод с таким
же именем и выводит новое сообщение.
Полиморфизм
Буквальный перевод слова полиморфизм (polymorphism) означает «много
форм». Лучшее определение полиморфизма звучит так: «полиморфизм – это способность (в программировании) представлять один и тот же интерфейс для различных базовых форм (типов данных)». Интерфейсом называют набор функций
или методов, не зависящих от конкретной реализации. Рассмотрим ситуацию,
в которой один и тот же интерфейс используется для разных типов данных:
print('Hello World!')
print(10)
print(15.2)
>> "Hello World!"
>> 10
>> 15.2
90
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
