Добавил:
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
- •Оператор деления по модулю
- •Сортировка методом пузырька
- •Поисковый алгоритм
- •Рекурсия
- •Абстрактные типы данных
- •Узлы
- •Стеки
- •Связанные списки
- •Массивы
- •Бинарные деревья
- •Поиск в ширину и в глубину
- •Хэш-таблицы
- •ЗАКЛЮЧЕНИЕ
- •БИБЛИОГРАФИЧЕСКИЙ СПИСОК

print(Pterodactyl)
>> <class '__main__.Pterodactyl'>
Язык Python превращает определение класса Pterodactyl в объект, ко-
торый можно использовать в программе, например, распечатав его. Следующий
пример аналогичен предыдущему:
class Square:
pass
print(Square)
>> <class '__main__.Square'>
Здесь выводится объект, которым является класс Square.
Переменные класса и переменные экземпляра класса
Классы могут иметь два типа переменных – переменные класса и пере-
менные экземпляра класса. Все переменные, которые встречались до сих пор,
были переменными экземпляра класса, определяемыми синтаксисом:
self.[имя_переменной] = [значение_переменной].
Переменные экземпляра класса принадлежат объекту, который их создал:
class Liger:
def __init__ (self, name):
self.name = name
connor = Liger("Connor")
print(connor.name)
>> Connor
Переменные класса принадлежат как классу, который их создал, так и объ-
екту. Это означает, что можно получить к ним доступ с помощью объекта класса, который Python создает для каждого класса:
class Liger:
interests = ["swimming", "eating", "sleeping"]
def __init__ (self, name):
self.name = name
print(Liger.interests)
>> ['swimming', 'eating', 'sleeping']
101

В этом примере не создавался объект Liger, но можно получить доступ
к переменной класса Interest. Это связано с тем, что к переменным класса
может обращаться создавший их класс. Переменные класса также могут быть
доступны объекту:
class Liger:
interests = ["swimming", "eating", "sleeping"]
def __init__ (self, name):
self.name = name
larry = Liger("Larry")
print(larry.interests)
>> ['swimming', 'eating', 'sleeping']
Переменные класса полезны, когда нужно, чтобы каждый объект в классе
имел доступ к переменной. В этом случае имя каждого Лигера может быть уникальным, но все Лигеры должны иметь доступ к одному и тому же списку интересов.
Для лучшего восприятия материала продемонстрируем обсуждаемые понятия на ставших уже классическими примерах, связанных с геометрическими
фигурами:
class Rectangle():
def __init__(self, w, l):
self.width = w
self.len = l
def print_size(self):
print("""{} на {}
""".format(self.width,8 self.len))
my_rectangle = Rectangle(10, 24)
my_rectangle.print_size()
>> 10 на 24
Здесь переменными экземпляра класса являются width и len.
Переменные класса принадлежат объекту, который Python создает для
каждого определения класса, и объектам, которые они создают. Переменные
102

класса определяются как обычные переменные (но определение осуществляется внутри класса). Можно получить к ним доступ с помощью объектов класса
и объектов, созданных объектами класса, как и к переменным экземпляра, добавляя перед именем переменной self. Переменные класса полезны – они
позволяют обмениваться данными между всеми экземплярами класса без полагания на глобальные переменные:
class Rectangle():
recs = []
def __init__(self, w, l):
self.width = w
self.len = l
self.recs.append((self.width, self.len))
def print_size(self):
print("""{} на {}
""".format(self.width, self.len))
r1 = Rectangle(10, 24)
r2 = Rectangle(20, 40)
r3 = Rectangle(100, 200)
print(Rectangle.recs)
>> [(10, 24), (20, 40), (100, 200)]
В этом фрагменте добавили переменную recs в класс Rectangle. Опре-
делили ее вне метода __init__, поскольку этот метод вызывается только при
создании объекта, а нужно получить доступ к переменной класса, используя
объект класса (что не вызывает метод __init__).
Затем были созданы три объекта Rectangle. Каждый раз, как создается
объект Rectangle, код в методе __init__ присоединяет кортеж, содержащий ширину и длину нового объекта, к списку recs. С помощью этого кода
каждый новый объект Rectangle автоматически добавляется в список recs.
Благодаря использованию переменной класса можно обменяться данными
между различными объектами, созданными классом, без необходимости использовать глобальную переменную.
103

Приватные переменные
Большинство языков программирования имеют концепцию приватных (закрытых) переменных и методов. Это специальные переменные и методы, которые может создать разработчик класса и к которым объект имеет доступ, но
программист, использующий объект, не имеет доступа. В одной ситуации приватные переменные и методы полезны, если есть метод или переменная в классе, которые класс использует внутри, но планируется позже изменить реализацию своего кода (или нужно сохранить гибкость, чтобы иметь возможность),
и, следовательно, не хотят, чтобы тот, кто использует класс, полагался на эти
переменные и методы, используемые внутри, потому что они могут измениться
(и затем нарушить код).
В отличие от других языков Python не имеет приватных переменных. Переменные, которые не являются приватными, называются общедоступными,
и все переменные Python являются общедоступными. Python решает проблему,
которую приватные переменные решают другим способом – используя соглашение. В Python, если есть переменная или метод, к которым вызывающий не
должен обращаться, то ставят перед ее именем символ подчеркивания. Программисты Python знают, что если у метода или переменной есть символ подчеркивания, им не следует его использовать, хотя можно это делать на свой
страх и риск. Вот пример класса, который использует это соглашение:
class PublicPrivateExample:
def __init__ (self):
self.public_variable = "callers know they can
access this"
self_dontusethisvariable ="callers know they
shouldn’t access
this"
def public_method(self):
# callers know they can use this method
pass
def _dont_use_this_method(self):
# callers know they shouldn’t use this method
pass
104

Программисты Python, читающие этот код, будут знать, что
self.public_variable безопасно использовать, но им не следует использовать self._dontusethisvariable, а если они это делают, то делают
это на свой страх и риск, потому что человек, поддерживающий этот код, не
обязан хранить self._dontusethisvariable, так как вызывающие
абоненты не должны иметь к ней доступ. То же самое касается двух методов:
программисты Python знают, что public_method безопасно использовать,
а _dont_use_this_method – нет.
Методы переопределения
Переопределением метода (англ. Method overriding) в ООП называется
возможность языка программирования, позволяющая дочернему классу обеспечивать специфическую реализацию метода, уже реализованного в одном из
родительских классов.
Таким образом, когда класс наследует родительский метод, есть возможность переопределить его.
Пример:
class Mammal:
def __init__ (self, name):
self.hunger = 100
self.tired = 100
self.name = name
def print_result(self, amount, action):
print("{} {} decreased by
{}.".format(self.name,
action, amount))
def eat(self, decrease):
self.hunger -= decrease
self.print_result(decrease, 'hunger')
def sleep(self, decrease):
self.tired -= decrease
self.print_result(decrease, 'tiredness')
class Dolphin(Mammal):
pass
105

class Tiger(Mammal):
def sleep(self ,decrease):
self.tired -= decrease
print("The tiger is really tired!")
dolphin = Dolphin('dolphin')
dolphin.eat(10)
dolphin.sleep(10)
tiger = Tiger('tiger')
tiger.eat(10)
tiger.sleep(10)
>> dolphin hunger decreased by 10.
>> dolphin tiredness decreased by 10.
>> tiger hunger decreased by 10.
>> The tiger is really tired!
В программе были созданы два класса, которые наследуются от Mammal.
Первый класс Dolphin наследует всю свою функциональность от родительского класса Mammal без внесения каких-либо изменений. Второй класс Tiger
определяет метод, называемый sleep, с функциональностью, отличной от метода sleep, который он унаследовал от своего родительского класса. Когда
вызывается tiger.sleep, вместо унаследованного метода вызывается новый
метод, который определили. Помимо этого, Tiger и Dolphin обладают всеми
теми же функциональными возможностями, унаследованными от родительского класса Mammal.
Функция super
Встроенная суперфункция позволяет вызывать метод класса, унаследованный от его родителя. Синтаксис:
super().[parent_method]([параметры]),
где parent_method заменяете родительским методом, который хотите вы-
звать, и передаете ему любые необходимые параметры. Затем вызывается и выполняется родительский метод, а остальная часть кода в методе, из которого
был вызван super, завершает выполнение. Вот пример того, как можно вызвать метод sleep родительского класса Mammal из метода sleep классов
106

Tiger, чтобы использовать код из метода sleep класса Mammal с последую-
щей дополнительной функциональностью:
class Tiger(Mammal):
def sleep(self, decrease):
super().sleep(decrease)
print("The tiger is really tired!")
tiger = Tiger('tiger')
tiger.eat(10)
tiger.sleep(10)
>> tiger tiredness decreased by 10.
>> The tiger is really tired!
Сначала используется ключевое слово super для вызова метода sleep
родительского класса Mammal и передается переменная уменьшения в качестве
параметра. Выполняется метод сна млекопитающего и выводится надпись
«усталость тигра уменьшилась на 10». Затем метод сна классов Tiger выполняет новую функциональность, которую добавили в метод сна классов Tiger,
и выводит сообщение «Тигр действительно устал!». Используя ключевое слово
super, вы смогли предоставить дочернему классу функциональность из метода родительского класса без необходимости повторно вводить функциональность в дочернем классе. Это важно, потому что всегда нужно избегать повторения кода с одной и той же функциональностью в разных местах вашей программы, когда это возможно.
Переопределение встроенных методов
Каждый класс в Python автоматически наследуется от родительского класса
с именем Object. Все классы в Python наследуют методы от этого родительского класса. Встроенные функции Python используют эти методы, называемые магическими методами, в разных ситуациях, например при печати объекта:
class Lion:
def __init__ (self, name):
self.name = name
lion = Lion("Dilbert")
print(lion)
>> <__main__.Lion object at 0x101178828>
107

При печати объекта Lion Python вызывает магический метод __repr__
для объекта, который он унаследовал от родительского класса Object. Он печатает все, что возвращает метод __repr__. Можно переопределить этот
встроенный метод, чтобы изменить то, что происходит, когда функция печати
печатает объект:
class Lion:
def __init__ (self, name):
self.name = name
def __repr__ (self):
return self.name
lion = Lion("Dilbert")
print(lion)
>> Dilbert
Поскольку метод __repr__ был переопределен, то при печати объекта
Lion имя объекта Lion – Dilbert печатается вместо чего-то вроде
<__main__.Lion object at 0x101178828>, которое вернул бы унасле-
дованный метод __repr__.
Не все магические методы передаются по наследству. Такие выражения,
как 2 + 2, предполагают, что операнды имеют метод, который оператор может
использовать для вычисления выражения. В примере 2 + 2 целочисленные объекты имеют метод __add__, который вызывается при вычислении выражения,
но __add__ не наследуется при создании класса. Можно создавать объекты,
которые затем используют в качестве операндов в выражении с оператором
сложения, определяя метод __add__ классе:
class AlwaysPositive:
def __init__ (self, number):
self.number = number
def __add__ (self, other):
return abs(self.number + other.number)
x = AlwaysPositive(-20)
y = AlwaysPositive(10)
print (x + y)
>> 10
108

Объекты AlwaysPositive можно использовать в качестве операндов
в выражении с оператором сложения, потому что определен метод с именем
__add__. Метод должен принимать второй параметр, поскольку при вычислении выражения с оператором сложения __add__ вызывается для первого объекта операнда, а второй объект операнда передается в __add__ в качестве параметра. Затем выражение возвращает результат __add__ .
В этом примере использовали функцию abs для возврата абсолютного
значения двух сложенных вместе чисел. Поскольку определили __add__ таким образом, что два объекта AlwaysPositive, сложенные вместе, всегда
будут возвращать абсолютное значение суммы двух объектов, то результат вы-
ражения всегда будет положительным.
12. Создание игр
В этой главе будем использовать то, что узнали о классах и объектах для
создания карточной игры «War». War – это игра, в которой каждый игрок берет
карту из колоды, и побеждает игрок с самой старшей картой. Создадим War,
определив класс, представляющий карту, колоду, игрока и, наконец, класс,
представляющий саму игру. Эти классы будут работать вместе, чтобы создать
игру War.
Карты
Сначала определим класс карты:
class Card:
suits = ["spades", "hearts", "diamonds", "clubs"]
values = [None, None, "2", "3", "4", "5",
"6", "7", "8", "9", "10",
"Jack", "Queen", "King", "Ace"]
def __init__ (self, value, suit):
"""suit and value should be integers"""
self.value = value
self.suit = suit
109

def __lt__ (self, other):
if self.value < other.value:
return True
if self .value == other.value:
if self .suit < other.suit:
return True
else:
return False
return False
def __gt__ (self, other):
if self.value > other.value:
return True
if self.value == other.value:
If self.suit > other.suit:
return True
else:
return False
return False
def __repr__ (self):
return self.values[self.value] + " of " +
self.suits[self.suit]
Класс Card имеет две переменные класса: suit и values. suits – это
список строк, представляющих все возможные масти карты. values – это спи-
сок строк, представляющих различные числовые значения, которые может
иметь карта. Первые два индекса значений равны None, чтобы строки в списке
совпадали с индексом, который они представляют, другими словами, чтобы
строка «2» в values располагалась по индексу 2.
Класс Card также имеет две переменные экземпляра: suit и values,
каждая из которых представлена целым числом. Определяют, к какому типу
карт относится объект Card. Например, можно создать двойку червей, создав
объект Card и передав параметры 2 и 1 (1 представляет червы, потому что
червы находятся под индексом один в списке мастей). Позже объект Card бу-
дет использовать эти переменные для вывода информации о том, что это за карта, используя их в качестве индексов в списках мастей и значений.
110
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
