Скачать презентацию Программирование на Python е Введение в информатику Глава 10 Скачать презентацию Программирование на Python е Введение в информатику Глава 10

Глава 10 Определение классов.ppt

  • Количество слайдов: 107

Программирование на Python’е: Введение в информатику Глава 10 Определение классов Python Programming, 2/e 1 Программирование на Python’е: Введение в информатику Глава 10 Определение классов Python Programming, 2/e 1

Задачи n n n Понимать как определение новых классов определяет структуру сложных программ. Уметь Задачи n n n Понимать как определение новых классов определяет структуру сложных программ. Уметь читать и писать определения классов на языке Python. Понимать концепцию инкапсуляции и то, как она способствует построению модульных и удобных в сопровождении программ. Python Programming, 2/e 2

Задачи n n Уметь писать программы с простыми классами. Уметь писать интерактивные графические программы Задачи n n Уметь писать программы с простыми классами. Уметь писать интерактивные графические программы включающие новые разработанные программистами виджеты (window gadgets -- графические элементы окна). Python Programming, 2/e 3

Быстрый обзор объектов n n n В последних трёх главах мы развили методы структуризации Быстрый обзор объектов n n n В последних трёх главах мы развили методы структуризации вычислений в программах. Мы теперь рассмотрим методы для структуризации данных, которые используют наши программы. До сих пор наши программы использовали объекты, созданные из заранее определённых классов, таких как Circle. В этой главе мы узнаем как писать свои собственные классы для создания новых объектов. Python Programming, 2/e 4

Быстрый обзор объектов В главе 4 объект был определён как активный тип данных, который Быстрый обзор объектов В главе 4 объект был определён как активный тип данных, который знает сущности и может делать сущности (имеет атрибуты и функциональность). Более точно объект состоит из: n n 1. 2. Набора связанных данных. Множества операций для манипулирования данными. Python Programming, 2/e 5

Быстрый обзор объектов n n n Данные хранятся внутри объекта в переменных экземпляра. Операции, Быстрый обзор объектов n n n Данные хранятся внутри объекта в переменных экземпляра. Операции, называемые методами, являются функциями, которые “живут” внутри объектов. Переменные экземпляров и методы вместе называются атрибутами объекта. Python Programming, 2/e 6

Быстрый обзор объектов n n Объект класса Circle будет иметь переменную экземпляра center, которая Быстрый обзор объектов n n Объект класса Circle будет иметь переменную экземпляра center, которая помнит координаты центральной точки круга, переменная radius, хранит длину радиуса круга. Метод draw получает значения переменных center и radius, чтобы решить какие пикселы окна следует закрасить. Python Programming, 2/e 7

Быстрый обзор объектов n n n Метод move изменяет значение переменной center, и задаёт Быстрый обзор объектов n n n Метод move изменяет значение переменной center, и задаёт новое положение круга. Все объекты являются экземплярами некоторого класса. Класс определяет какие характерные черты будут у объекта класса. Класс это описание того, что экземпляры знают и что умеют делать. Python Programming, 2/e 8

Быстрый обзор объектов n n Для данного класса новые объекты создаются с помощью конструктора. Быстрый обзор объектов n n Для данного класса новые объекты создаются с помощью конструктора. Класс можно себе представить как фабрику по штамповке новых экземпляров объектов. Рассмотрим создание нового круга (объекта класса circle): my. Circle = Circle(Point(0, 0), 20) n Имя класса Circle используется для вызова конструктора. Python Programming, 2/e 9

Быстрый обзор объектов my. Circle = Circle(Point(0, 0), 20) n n Этот оператор создаёт Быстрый обзор объектов my. Circle = Circle(Point(0, 0), 20) n n Этот оператор создаёт экземпляр класса Circle и сохраняет ссылку на него в переменной my. Circle. Параметры конструктора используются для инициализации некоторых переменных экземпляра (center и radius) круга, задаваемого переменной my. Circle. Python Programming, 2/e 10

Быстрый обзор объектов my. Circle = Circle(Point(0, 0), 20) n Как только экземпляр создан, Быстрый обзор объектов my. Circle = Circle(Point(0, 0), 20) n Как только экземпляр создан, с ним можно работать, вызывая его методы: my. Circle. draw(win) my. Circle. move(dx, dy) Python Programming, 2/e 11

Спецификации программы «Полёт ядра» n n Давайте напишем программу, которая имитирует полёт пушечного ядра Спецификации программы «Полёт ядра» n n Давайте напишем программу, которая имитирует полёт пушечного ядра или другого летающего предмета. Нас интересует как далеко пролетит пушечное ядро, когда его выстреливают под разными углами и с разными начальными скоростями. Python Programming, 2/e 12

Спецификации программы «Полёт ядра» n n Ввод в программу будет состоять из угла стрельбы Спецификации программы «Полёт ядра» n n Ввод в программу будет состоять из угла стрельбы (в градусах), начальной скорости (в метрах в секунду), и начальной высоты (в метрах) пушечного ядра. Выводом будет расстояние, которое пройдёт ядро (в метрах), до удара о землю. Python Programming, 2/e 13

Спецификации программы «Полёт ядра» n n Ускорение силы тяжести около поверхности Земли приблизительно равно Спецификации программы «Полёт ядра» n n Ускорение силы тяжести около поверхности Земли приблизительно равно 9. 8 м/с2. Если объект брошен прямо вверх со скоростью 20 м/с, после одной секунды будет лететь со скоростью 10. 2 м/с. После второй секунды скорость будет 0. 4 м/с. Вскоре после этого объект начнёт падать вниз. Python Programming, 2/e 14

Спецификации программы «Полёт ядра» n n Используя математический анализ, мы можем вывести точную формулу, Спецификации программы «Полёт ядра» n n Используя математический анализ, мы можем вывести точную формулу, которая задаёт позицию пушечного ядра в любой момент его полёта. Вместо этого, мы решим проблему с помощью моделирования, геометрии, и того факта, что расстояние, которое объект проходит за определённый период времени, равно подходящему значению скорости, умноженной на время (d = rt). Python Programming, 2/e 15

Проектирование программы n n Принимая во внимание природу проблемы, очевидно, что нам следует рассматривать Проектирование программы n n Принимая во внимание природу проблемы, очевидно, что нам следует рассматривать полёт в двух измерениях: по высоте и по горизонтали. Давайте представлять положение пушечного ядра как точку с координатами (x, y), где x расстояние от точки старта по горизонтали, и y высота над землёй. Python Programming, 2/e 16

Проектирование программы n n Предположим, что ядро стартует из позиции (0, 0), и мы Проектирование программы n n Предположим, что ядро стартует из позиции (0, 0), и мы проверяем его положение каждую десятую секунды. За этот период времени ядро проходит некоторое расстояние по вертикали (значение y) и некоторое расстояние по горизонтали (значение x). Значение расстояния в интересующем направлении находится по скорости в этом направлении. Python Programming, 2/e 17

Проектирование программы n n Так как мы пренебрегаем сопротивлением воздуха, то скорость в направлении Проектирование программы n n Так как мы пренебрегаем сопротивлением воздуха, то скорость в направлении x остаётся постоянной в течение всего времени полёта. Вместе с тем скорость в направлении y будет изменяться из-за силы тяжести. Сначала скорость в направлении y будет положительной, а затем, когда ядро начнёт падать, станет отрицательной. Python Programming, 2/e 18

Проектирование программы n n Ввод параметров моделирования: угол, скорость, высота, приращение времени. Вычисляем начальное Проектирование программы n n Ввод параметров моделирования: угол, скорость, высота, приращение времени. Вычисляем начальное положение ядра: xpos, ypos Вычисляем начальные скорости ядра: xvel, yvel Пока ядро летит: n n Актуализируем значения xpos, ypos, и yvel для приращения времени Выводим пройденное расстояние (xpos) Python Programming, 2/e 19

Проектирование программы n Использование пошагового улучшения: def main(): angle = eval(input( Проектирование программы n Использование пошагового улучшения: def main(): angle = eval(input("Введите угол запуска ядра(в градусах): ")) vel = eval(input("Введите начальную скорость(в м/с): ")) h 0 = eval(input("Введите начальную высоту (в метрах): ")) time = eval(input("Введите приращение времени между вычислениями положений: ")) n Положение начального положения ядра несложно. Оно находится на расстоянии 0 и на высоте h 0! xpos = 0 ypos = h 0 Python Programming, 2/e 20

Проектирование программы n Если мы знаем значение скорости и угла theta, мы можем тогда Проектирование программы n Если мы знаем значение скорости и угла theta, мы можем тогда написать yvel=velocity*sin(theta)и xvel=velocity*cos(theta). Python Programming, 2/e 21

Проектирование программы n n n Мы ввели угол angle в градусах, а математическая библиотека Проектирование программы n n n Мы ввели угол angle в градусах, а математическая библиотека Python’а использует радианы, поэтому theta = ( *angle)/180. theta = (angle * pi)/180. 0 xvel = vel * cos(theta) yvel = vel * sin(theta) В основном цикле мы хотим актуализировать положение ядра до тех пор пока ядро не достигнет земли: while ypos >= 0. 0: n Мы пишем >= 0, чтобы цикл начинался и тогда, когда стреляют с уровня земли. Python Programming, 2/e 22

Проектирование программы n n При всяком проходе цикла мы хотим актуализировать положение ядра, продвинуть Проектирование программы n n При всяком проходе цикла мы хотим актуализировать положение ядра, продвинуть его на time секунд дальше. Так как мы предполагаем, что сопротивления воздуха нет, то составляющая xvel остаётся постоянной. Предположим, что ядро движется со скоростью 30 м/с и находится в 50 м от стартовой точки. Через секунду оно будет на расстоянии (50 + 30) метров. Если приращение времени =. 1 секунды, то расстояние будет (50 + 30*. 1) = 53 meters. xpos = xpos + time * xvel Python Programming, 2/e 23

Проектирование программы n n Работа с yvel немного затруднительнее, потому что гравитация заставляет yскорость Проектирование программы n n Работа с yvel немного затруднительнее, потому что гравитация заставляет yскорость изменяться по времени. Каждую секунду yvel уменьшается на 9. 8 м/с, из-за ускорения, вызываемого гравитацией. Через 0. 1 секунды скорость будет 0. 1*(9. 8) м/с=. 98 м/с. yvel 1 = yvel - 9. 8 * time Python Programming, 2/e 24

Проектирование программы n n n Чтобы вычислить как далеко ядро продвинется по вертикали за Проектирование программы n n n Чтобы вычислить как далеко ядро продвинется по вертикали за время приращения, нам нужно вычислить среднюю скорость за время приращения. Так как скорость уменьшения скорости, вызываемая гравитацией, постоянна, то это просто среднее начальной и конечной скорости. Среднюю скорость умножаем на время приращения: ypos = ypos + time * (yvel + yvel 1)/2. 0 Python Programming, 2/e 25

Проектирование программы # cball 1. py # Моделирование полёта пушечного ядра (или другого летательного Проектирование программы # cball 1. py # Моделирование полёта пушечного ядра (или другого летательного средства) # Эта версия не модульная. from math import pi, sin, cos def main(): angle = eval(input("Введите угол запуска ядра(в градусах): ")) vel = eval(input("Введите начальную скорость(в м/с): ")) h 0 = eval(input("Введите начальную высоту (в метрах): ")) time = eval(input("Введите приращение времени между вычислениями положений: ")) radians = (angle * pi)/180. 0 xpos = 0 ypos = h 0 xvel = vel * cos(radians) yvel = vel * sin(radians) while ypos >= 0: xpos = xpos + time * xvel yvel 1 = yvel - 9. 8 * time ypos = ypos + time * (yvel + yvel 1)/2. 0 yvel = yvel 1 print("n. Пройденное расстояние: {0: 0. 1 f} метров. ". format(xpos) main() Python Programming, 2/e 26

Модульное представление программы n n Во время разработки программы мы использовали пошаговое улучшение программы Модульное представление программы n n Во время разработки программы мы использовали пошаговое улучшение программы и разработку сверху вниз, но не делили программы на функции. Эта программа достаточно коротка, но и достаточно сложна, из-за числа переменных. Python Programming, 2/e 27

Модульное представление программы def main(): angle, vel, h 0, time = get. Inputs() xpos, Модульное представление программы def main(): angle, vel, h 0, time = get. Inputs() xpos, ypos = 0, h 0 xvel, yvel = get. XYComponents(vel, angle) while ypos >= 0: xpos, yvel = update. Cannon. Ball(time, xpos, ypos, xvel, yvel) print("n. Пройденное расстояние: {0: 0. 1 f} метров. ". format(xpos) n Должно быть понятно, что содержание каждой из вспомогательных функций действительно определяется её именем и первоначальным программным кодом. Python Programming, 2/e 28

Модульное представление программы n n n Эта версия программы более точна. Число переменных уменьшилось Модульное представление программы n n n Эта версия программы более точна. Число переменных уменьшилось с 10 до 8, так как переменные theta и yvel 1 стали локальными для функций get. XYComponents и update. Cannon. Ball, соответственно. Это проще, но всё равно, отслеживание положения ядра требует 4 вида данных, 3 из которых меняются со временем. Python Programming, 2/e 29

Модульное представление программы n n n Все 4 переменных плюс переменная time, необходимы для Модульное представление программы n n n Все 4 переменных плюс переменная time, необходимы для вычисления новых значений трёх переменных, которые изменяются. Это даёт нам функцию с пятью параметрами и тремя возвращаемыми значениями. Уф! Должен быть способ получше. Python Programming, 2/e 30

Модульное представление программы n n Существует единственный физический объект пушечное ядро, но он требует Модульное представление программы n n Существует единственный физический объект пушечное ядро, но он требует 4 вида данных: xpos, ypos, xvel, x и yvel. Предположим, что класс Projectile «понимает» физику такого объекта как пушечное ядро. Алгоритм, использующий этот подход, создаст и актуализирует объект, хранящийся в единственной переменной. Python Programming, 2/e 31

Модульное представление программы n Используем объектно-ориентированный подход: def main(): angle, vel, h 0, time Модульное представление программы n Используем объектно-ориентированный подход: def main(): angle, vel, h 0, time = get. Inputs() cball = Projectile(angle, vel, h 0) while cball. get. Y() >= 0: cball. update(time) print("n. Пройденное расстояние: {0: 0. 1 f} метров. ". format(cball. get. X())) main() n Чтобы этот код работал, нам нужен класс Projectile, который содержит методы update, get. X, и get. Y. Python Programming, 2/e 32

Пример: многосторонние игральные кости n n n Обычная игральная кость это куб с шестью Пример: многосторонние игральные кости n n n Обычная игральная кость это куб с шестью сторонами, каждая с номером от 1 до 6. Некоторые игры используют специальные кости с разными наборами сторон. Давайте спроектируем общий класс MSDie, чтобы смоделировать многосторонние игральные кости. Python Programming, 2/e 33

Пример: многосторонние игральные кости n Каждый объект класса MSDie знает две вещи: n n Пример: многосторонние игральные кости n Каждый объект класса MSDie знает две вещи: n n n Сколько у него сторон. Своё текущее значение Когда создаётся новый объект класса MSDie, мы определяем n, число сторон, которое он будет иметь. Python Programming, 2/e 34

Пример: многосторонние игральные кости n У нас есть три метода, чтобы обращаться с игральной Пример: многосторонние игральные кости n У нас есть три метода, чтобы обращаться с игральной костью: n roll – назначает кости случайное значение от 1 до n включительно. n set. Value – устанавливает у кости конкретное значение. (например, 4) n get. Value – смотрит чему равно текущее значение. Python Programming, 2/e 35

Пример: многосторонние игральные кости >>> 1 >>> 5 >>> 1 >>> 9 >>> 8 Пример: многосторонние игральные кости >>> 1 >>> 5 >>> 1 >>> 9 >>> 8 die 1 = MSDie(6) die 1. get. Value() die 1. roll() die 1. get. Value() die 2 = MSDie(13) die 2. get. Value() die 2. roll() die 2. get. Value() die 2. set. Value(8) die 2. get. Value() Python Programming, 2/e 36

Пример: многосторонние игральные кости n n n Используя наш объектно-ориентированный словарь, мы создаём игральную Пример: многосторонние игральные кости n n n Используя наш объектно-ориентированный словарь, мы создаём игральную кость, вызывая конструктор MSDie и предоставляя число сторон как параметр. Наши объекты-кости будут хранить эти числа внутри себя в переменной экземпляра. Другая переменная экземпляра используется чтобы хранить текущее значение игральной кости. Первоначально мы устанавливаем значение кости в 1, потому что это значение может выпасть у любой кости. Это значение можно изменить методом roll и set. Value, и возвратить его методом get. Value. Python Programming, 2/e 37

Пример: многосторонние игральные кости # msdie. py # Определение класса для n-сторонней кости. from Пример: многосторонние игральные кости # msdie. py # Определение класса для n-сторонней кости. from random import randrange class MSDie: def __init__(self, sides): self. sides = sides self. value = 1 def roll(self): self. value = randrange(1, self. sides+1) def get. Value(self): return self. value def set. Value(self, value): self. value = value Python Programming, 2/e 38

Пример: многосторонние игральные кости n Определение класса class <имя-класса>: <определения-методов> n n Методы выглядят Пример: многосторонние игральные кости n Определение класса class <имя-класса>: <определения-методов> n n Методы выглядят во многом как функции. Помещение функции в класс превращает её методом класса, из отдельной функции. Первый параметр метода всегда называется self, что является ссылкой на объект, на котором действует метод. Python Programming, 2/e 39

Пример: многосторонние игральные кости n n Предположим у нас есть функция main, которая выполняет Пример: многосторонние игральные кости n n Предположим у нас есть функция main, которая выполняет метод die 1. set. Value(8). Как и при вызовах функции Python выполняет следующую 4 -шаговую последовательность: n программа main зависает в точке применения метода. Python находит нужное определение метода внутри класса объекта, к которому применяется метод. Здесь управление передаётся set. Value класса MSDie так как die 1 экземпляр класса MSDie. Python Programming, 2/e 40

Пример: многосторонние игральные кости n n Формальные параметры метода получают значения фактических параметров вызова. Пример: многосторонние игральные кости n n Формальные параметры метода получают значения фактических параметров вызова. Когда вызывается метод, то первым формальным параметром является ссылка на объект: self = die 1 value = 8 Выполняется тело метода. Python Programming, 2/e 41

Пример: многосторонние игральные кости n n Управление передаётся в точку, расположенную сразу после той, Пример: многосторонние игральные кости n n Управление передаётся в точку, расположенную сразу после той, из которой был вызван метод. die 1. set. Value(8). Метод вызван с одним параметром, но определение метода включает параметр self и имеющийся параметр. Python Programming, 2/e 42

Пример: многосторонние игральные кости n Параметр self это вспомогательная деталь. Мы можем ссылаться на Пример: многосторонние игральные кости n Параметр self это вспомогательная деталь. Мы можем ссылаться на первый формальный параметр как на параметр self , а на другие параметры как на нормальные параметры. Так можно сказать, что у метода set. Value один нормальный параметр. Python Programming, 2/e 43

Пример: многосторонние игральные кости Python Programming, 2/e 44 Пример: многосторонние игральные кости Python Programming, 2/e 44

Пример: многосторонние игральные кости n n n Объекты содержат свои собственные данные. Переменные экземпляра Пример: многосторонние игральные кости n n n Объекты содержат свои собственные данные. Переменные экземпляра предоставляют место хранения данных внутри объекта. Переменные экземпляра обозначаются с помощью точечной нотации: <объект>. <переменная экземпляра> Посмотрев на тело метода set. Value, мы видим, что self. value ссылается на переменную экземпляра value внутри объекта. У каждого объекта класса MSDie своя переменная value. Python Programming, 2/e 45

Пример: многосторонние игральные кости n n Некоторые методы имеют специальное значение. У этих методов Пример: многосторонние игральные кости n n Некоторые методы имеют специальное значение. У этих методов имена начинаются и заканчиваются на два символа подчеркивания ’_’. Метод __init__ это конструктор объекта. Python вызывает этот метод, чтобы инициализировать новый объект класса MSDie. Метод __init__ снабжает начальными значениями переменные нового объекта. Python Programming, 2/e 46

Пример: многосторонние игральные кости n n n Вне класса к конструктору обращаются через имя Пример: многосторонние игральные кости n n n Вне класса к конструктору обращаются через имя класса: die 1 = MSDie(6) Когда выполняется такая команда, создаётся новый объект класса MSDie и метод __init__ выполняется на этом объекте. Окончательным результатом является то, что переменной die 1. sides присваивается значение 6, а die 1. value – значение 1. Python Programming, 2/e 47

Пример: многосторонние игральные кости n n Переменные экземпляра могут запомнить состояние данного объекта, и Пример: многосторонние игральные кости n n Переменные экземпляра могут запомнить состояние данного объекта, и эти данные можно передавать в программе как часть объекта. Это отличается от локальных переменных функции, значения которых исчезают, когда функция заканчивает работу. Python Programming, 2/e 48

Пример: класс ядра n n В случае класса метательного предмета нужен конструктор, который инициализирует Пример: класс ядра n n В случае класса метательного предмета нужен конструктор, который инициализирует переменные экземпляра и метод update, который изменяет положение предмета, и методы get. X и get. Y, которые сообщают о текущем положении. В программе main экземпляр пушечного ядра можно создать, задав начальные угол, скорость и высоту: cball = Projectile(angle, vel, h 0) Python Programming, 2/e 49

Пример: класс ядра n n Класс Projectile должен иметь метод __init__, который использует эти Пример: класс ядра n n Класс Projectile должен иметь метод __init__, который использует эти значения для инициализации переменных экземпляра cball. Эти значения вычисляются по тем же формулам, что и ранее. Python Programming, 2/e 50

Пример: класс ядра class Projectile: def __init__(self, angle, velocity, height): self. xpos = 0. Пример: класс ядра class Projectile: def __init__(self, angle, velocity, height): self. xpos = 0. 0 self. ypos = height theta = pi * angle / 180. 0 self. xvel = velocity * cos(theta) self. yvel = velocity * sin(theta) n Мы создали четыре переменных экземпляра (self. ? ? ? ). Так как значение переменной theta далее не нужно, то это нормальная переменная функции. Python Programming, 2/e 51

Пример: класс ядра n Методы для получения значений X и Y прямолинейны: def get. Пример: класс ядра n Методы для получения значений X и Y прямолинейны: def get. Y(self): return self. ypos def get. X(self): return self. xpos Python Programming, 2/e 52

Пример: класс ядра n Последний метод update, в котором мы берём временной интервал и Пример: класс ядра n Последний метод update, в котором мы берём временной интервал и вычисляем актуализированные значения X и Y. def update(self, time): self. xpos = self. xpos + time * self. xvel yvel 1 = self. yvel - 9. 8 * time self. ypos = self. ypos + time * (self. yvel + yvel 1) / 2. 0 self. yvel = yvel 1 n Переменная yvel 1 является временной. Python Programming, 2/e 53

Пример: класс ядра n n Класс полезен для моделирования объектов реального мира со сложным Пример: класс ядра n n Класс полезен для моделирования объектов реального мира со сложным поведением. Другим стандартным применением объектов является группировка множества данных, которые описывают объект или событие. n Например, компании нужно следить за данными о работающих (класс Employee с данными о работниках, такими как Фамилия, Табельный номер, Адрес, Зарплата, и т. д. ) Python Programming, 2/e 54

Обработка данных с использованием классов n n n Сгруппированные таким образом данные часто называют Обработка данных с использованием классов n n n Сгруппированные таким образом данные часто называют записями. Давайте попробуем простой пример обработки данных. Обычный университет измеряет курсы в терминах часов курсов и средних оценок, которые вычисляются по 4 -х бальной системе, где “A” это 4 бала, “B” это 3 бала и т. д. Python Programming, 2/e 55

Обработка данных с использованием классов n Средние оценок обычно вычисляются, используя квалификационные балы. Если Обработка данных с использованием классов n Средние оценок обычно вычисляются, используя квалификационные балы. Если курс стоит 3 часа и студент получает оценку “A”, тогда он или она получает 3*4 = 12 квалификационных балов. Чтобы вычислить среднюю оценку (GPA), мы делим общее количество квалификационных балов на общее количество часов всех сданных курсов. Python Programming, 2/e 56

Обработка данных с использованием классов n n Предположим, что у нас есть файл с Обработка данных с использованием классов n n Предположим, что у нас есть файл с данными об оценках студентов. Каждая строка файла состоит из фамилии студента, прослушанных часов, и квалификационных балов. Adams, Henry Comptewell, Susan Dibble. Bit, Denny Jones, Jim Smith, Frank 127 100 18 48. 5 37 Python Programming, 2/e 228 400 41. 5 155 125. 33 57

Обработка данных с использованием классов n n n Наша задача написать программу, которая читает Обработка данных с использованием классов n n n Наша задача написать программу, которая читает записи файла находит студента с наилучшей средней оценкой и печатает его фамилию часы и среднюю оценку. С чего начать? С создания класса Student. Мы можем использовать объект класса Student, чтобы читать в него данные об очередном студенте и сохранять их как значения переменных экземпляра. Python Programming, 2/e 58

Обработка данных с использованием классов n n class Student: def __init__(self, name, hours, qpoints): Обработка данных с использованием классов n n class Student: def __init__(self, name, hours, qpoints): self. name = name self. hours = float(hours) self. qpoints = float(qpoints) Значение переменной hours преобразовано в тип float, чтобы работать со значениями, которые могут иметь тип float, int, или string. Создаём запись о студенте: a. Student = Student(“Adams, Henry”, 127, 228) Самая крутая вещь заключается в том, что мы можем хранить все данные об одном студенте в одной переменной. Python Programming, 2/e 59

Обработка данных с использованием классов n n Нам нужно уметь извлекать введённые данные, поэтому Обработка данных с использованием классов n n Нам нужно уметь извлекать введённые данные, поэтому нужны методы для извлечения данных. def get. Name(self): return self. name def get. Hours(self): return self. hours def get. QPoints(self): return self. qpoints def gpa(self): return self. qpoints/self. hours n Например, чтобы напечатать фамилию студента, можно написать: print a. Student. get. Name() Python Programming, 2/e 60

Обработка данных с использованием классов n n Как использовать все эти инструменты для нахождения Обработка данных с использованием классов n n Как использовать все эти инструменты для нахождения студента с наилучшей средней оценкой? Можно использовать алгоритм, похожий на нахождение максимума из n чисел. Можно просматривать список один за одним, сохраняя данные о лучшем студенте, виденном до настоящего момента. Python Programming, 2/e 61

Обработка данных с использованием классов Получаем имя файла от пользователя Открываем файл для чтения Обработка данных с использованием классов Получаем имя файла от пользователя Открываем файл для чтения Первоначально считаем лучшим первого студента Для каждого студента s в файле if s. gpa() > best. gpa считай лучшим студента s Напечатай данные лучшего студента Python Programming, 2/e 62

Обработка данных с использованием классов # gpa. py # Программа нахождения студента с лучшей Обработка данных с использованием классов # gpa. py # Программа нахождения студента с лучшей средней оценкой class Student: def __init__(self, name, hours, qpoints): self. name = name self. hours = float(hours) self. qpoints = float(qpoints) def get. Name(self): return self. name def get. Hours(self): return self. hours def main(): filename = input("Введите имя файла с оценками: ") infile = open(filename, 'r') best = make. Student(infile. readline()) for line in infile: s = make. Student(line) if s. gpa() > best. gpa(): best = s infile. close() print("The best student is: ", best. get. Name()) print ("hours: ", best. get. Hours()) print("GPA: ", best. gpa()) if __name__ == '__main__': main() def get. QPoints(self): return self. qpoints def gpa(self): return self. qpoints/self. hours def make. Student(info. Str): name, hours, qpoints = info. Str. split("t") return Student(name, hours, qpoints) Python Programming, 2/e 63

Инкапсуляция полезных абстракций n n Определение новых классов (таких как Projectile и Student) может Инкапсуляция полезных абстракций n n Определение новых классов (таких как Projectile и Student) может способствовать повышению модульности программы. Как только определены полезные объекты, детали их реализации из алгоритма можно переместить в определение соответствующего класса. Python Programming, 2/e 64

Инкапсуляция полезных абстракций n n n Основная программа должна беспокоиться только о том, что Инкапсуляция полезных абстракций n n n Основная программа должна беспокоиться только о том, что объект может делать, а не о том, как объекты реализованы. В информатике это разделение называют инкапсуляцией. Детали реализации объекта инкапсулированы в определение класса, которое изолирует оставшуюся программу от необходимости иметь с ними дело. Python Programming, 2/e 65

Инкапсуляция полезных абстракций n n Одна из основных причин почему следует использовать объекты заключается Инкапсуляция полезных абстракций n n Одна из основных причин почему следует использовать объекты заключается в сокрытии сложностей объектов от программ, которые их используют. Снаружи класса, все взаимодействия с объектом данного класса могут осуществляться только с помощью интерфейса, предоставляемого методами класса. Python Programming, 2/e 66

Инкапсуляция полезных абстракций n Одним из достоинств этого подхода является то, что он позволяет Инкапсуляция полезных абстракций n Одним из достоинств этого подхода является то, что он позволяет нам актуализировать и улучшать классы независимо, без боязни «испортить» другие части программы, при условии сохранения имеющегося интерфейса без изменений. Python Programming, 2/e 67

Помещение классов в модули n n Иногда мы можем создать класс, который мог бы Помещение классов в модули n n Иногда мы можем создать класс, который мог бы быть полезен во многих других программах. Чтобы можно было использовать код снова, его следует поместить в отдельный модульный файл, содержащий подробную документацию, описывающую, как класс следует использовать, чтобы это не нужно было в будущем разгадывать, исходя из голого кода. Python Programming, 2/e 68

Документирование модулей n n Вы уже знакомы со знаком “#”, который означает комментарии, объясняющие, Документирование модулей n n Вы уже знакомы со знаком “#”, который означает комментарии, объясняющие, что происходит в файле Python’а. Python также содержит специальный вид соглашений по комментированию, называемых цепочка документации. Вы можете вставить простой литерал как первую строку модуля класса или функции, чтобы документировать нужный компонент. Python Programming, 2/e 69

Документирование модулей n Зачем использовать цепочки документации? n n n Обычные комментарии игнорируются Python’ом Документирование модулей n Зачем использовать цепочки документации? n n n Обычные комментарии игнорируются Python’ом Строки документации доступны в специальном описателе, называемом __doc__. Большинство библиотечных модулей Python’а имеют пространные цепочки документации. Например, если вы не можете вспомнить как использовать random: >>> import random >>> print random. __doc__ random() -> x in the interval [0, 1). Python Programming, 2/e 70

Документирование модулей n Цепочки документации используются также в диалоговой системе помощи Python’а и утилитой, Документирование модулей n Цепочки документации используются также в диалоговой системе помощи Python’а и утилитой, называемой Py. Doc, который автоматически строит документацию для модулей Python’а. Вы можете получить те же данные, как внизу: >>> import random >>> help(random) Help on built-in function random: random(. . . ) random() -> x in the interval [0, 1). Python Programming, 2/e 71

Документирование модулей n n Чтобы посмотреть документацию ко всему модулю, попробуйте написать help(module_name)! Следующий Документирование модулей n n Чтобы посмотреть документацию ко всему модулю, попробуйте написать help(module_name)! Следующий код для класса Projectile содержит цепочку документации. Python Programming, 2/e 72

Документирование модулей # projectile. py Документирование модулей # projectile. py """projectile. py Предоставляет простой класс для моделирования полета бросаемых тел. """ from math import pi, sin, cos class Projectile: """Моделирует полёт простого бросаемого тела вблизи поверхности земли, не учитывает сопротивление воздуха. Отслеживание производится по двум измерениям, по высоте (y) и по горизонтали (x). """ def __init__(self, angle, velocity, height): """Создаёт бросаемое тело с заданным углом запуска, начальной скоростью и высотой. """ self. xpos = 0. 0 self. ypos = height theta = pi * angle / 180. 0 self. xvel = velocity * cos(theta) self. yvel = velocity * sin(theta) Python Programming, 2/e 73

Документирование модулей def update(self, time): Документирование модулей def update(self, time): """Актуализирует положение тела в полёте каждые time секунд. """ self. xpos = self. xpos + time * self. xvel yvel 1 = self. yvel - 9. 8 * time self. ypos = self. ypos + time * (self. yvel + yvel 1) / 2. 0 self. yvel = yvel 1 def get. Y(self): "Возвращает высоту y метаемого тела. " return self. ypos def get. X(self): "Возвращает расстояние x метаемого тела. " return self. xpos Python Programming, 2/e 74

Работа с использованием нескольких модулей n Наша программа main импортирует из модуля Projectile, чтобы Работа с использованием нескольких модулей n Наша программа main импортирует из модуля Projectile, чтобы решать свои задачи # cball 4. py # Simulation of the flight of a cannon ball (or other projectile) # This version uses a separate projectile module file from projectile import Projectile def get. Inputs(): a = eval(input("Введите v = eval(input("Введите h = eval(input("Введите t = eval(input("Введите return a, v, h, t угол запуска ядра (в градусах): ")) начальную скорость(в м/с): ")) начальную высоту (в метрах): ")) приращение времени между вычислениями положений : ")) def main(): angle, vel, h 0, time = get. Inputs() cball = Projectile(angle, vel, h 0) while cball. get. Y() >= 0: cball. update(time) print("n. Пройденное расстояние: {0: 0. 1 f} meters. ". format(cball. get. X()) Python Programming, 2/e 75

Работа с использованием нескольких модулей n n Если вы тестируете многомодульную программу на Python’е, Работа с использованием нескольких модулей n n Если вы тестируете многомодульную программу на Python’е, то вам нужно знать, что перезагрузка модуля может повести себя не так как вы ожидаете. Когда Python впервые импортирует данный модуль, он создаёт модульный объект, который содержит всё содержимое модуля (отраженное в пространстве имён). Если модуль импортирован успешно (нет синтаксических ошибок), то последующие импортирования не перезагружают модуль. Даже если исходный текст модуля изменился, повторный импорт модуля в той же интерактивной сессии не загрузит актуализированную версию. Python Programming, 2/e 76

Работа с использованием нескольких модулей n Простейший способ загрузить актуализированную версию модуля – начинать Работа с использованием нескольких модулей n Простейший способ загрузить актуализированную версию модуля – начинать новую интерактивную сессию для тестирования, всякий раз, когда любой из модулей, участвующий в тестировании, изменился. Таким способом вы гарантируете, что при импорте получите самые свежие модули, которые вы используете. Python Programming, 2/e 77

Виджет (графический элемент окна) n n n Одним из наиболее стандартных использований объектов является Виджет (графический элемент окна) n n n Одним из наиболее стандартных использований объектов является проектирование графического интерфейса пользователя (ГИП). В главе 5 мы говорили о том, что ГИП составляется из графических элементов (виджетов). Объект Entry определённый в библиотеке graphics один из примеров виджетов. Python Programming, 2/e 78

Пример программы: бросание игральных костей n n n Давайте построим пару полезных виджетов. Рассмотрим Пример программы: бросание игральных костей n n n Давайте построим пару полезных виджетов. Рассмотрим программу, которая бросает пару шестисторонних игральных костей. Программа представляет игральную кость графически и предоставляет две кнопки, одну для бросания костей, другую для выхода из программы. Python Programming, 2/e 79

Пример программы: бросание игральных костей n n Справа два виджетов: кнопки и кости. Две Пример программы: бросание игральных костей n n Справа два виджетов: кнопки и кости. Две кнопки пример класса Button, а образы костей даются классом die. View. Python Programming, 2/e 80

Создание кнопок n n Наиболее современные ГИП имеют кнопки с 3 -мерным видом и Создание кнопок n n Наиболее современные ГИП имеют кнопки с 3 -мерным видом и ощущением. Наш простой графический пакет не обладает способностями создавать кнопки, которые производят впечатление опускания, когда на них нажимают. Всё, что мы можем сделать это проинформировать, где был произведён щелчок, после того как он был произведён. Python Programming, 2/e 81

Создание кнопок n n n Наши кнопки будут прямоугольными областями в графическом окне, в Создание кнопок n n n Наши кнопки будут прямоугольными областями в графическом окне, в которых щелчок пользователя может повлиять на поведение исполняемого приложения. Нам нужен способ определить был ли произведён щелчок по кнопке. Было бы хорошо уметь активировать и деактивировать (делать серыми) отдельные кнопки. Python Programming, 2/e 82

Создание кнопок n n n Конструктор – Создаёт кнопку в окне. Мы будем задавать Создание кнопок n n n Конструктор – Создаёт кнопку в окне. Мы будем задавать окно, положение/размер кнопки, надпись на кнопке. Активировать – Установить состояние кнопки в активное. Деактивировать – Установить состояние кнопки в неактивное. Python Programming, 2/e 83

Создание кнопок n n Щелкнуто – Указывает, что по кнопке щелкнули. Если кнопка была Создание кнопок n n Щелкнуто – Указывает, что по кнопке щелкнули. Если кнопка была активна, то метод определит, что точка по которой щелкнули, находится внутри области кнопки. Точку нужно послать как параметр в метод. get. Label – Возвращает надпись на кнопке. Метод нужен для того, чтобы мы могли идентифицировать заданную кнопку. Python Programming, 2/e 84

Создание кнопок n n Чтобы поддерживать эти операции, нашим кнопкам необходим ряд переменных экземпляров. Создание кнопок n n Чтобы поддерживать эти операции, нашим кнопкам необходим ряд переменных экземпляров. Например, кнопки рисуются как прямоугольники, с некоторым текстом, отцентрованным в них. Вызов методов activate и deactivate изменяет вид кнопок. Python Programming, 2/e 85

Создание кнопок n n Сохранение объектов классов Rectangle и Text как переменных экземпляров означает, Создание кнопок n n Сохранение объектов классов Rectangle и Text как переменных экземпляров означает, что мы будем способны управлять шириной контура и цветом надписи. Давайте попробуем написать эти методы и построить список возможных переменных экземпляров. Как только у нас будет список, мы сможем написать конструктор, чтобы инициализировать их. Python Programming, 2/e 86

Создание кнопок n n n В методе activate, мы можем сообщить, что кнопка активна, Создание кнопок n n n В методе activate, мы можем сообщить, что кнопка активна, сделав её контур толще, а текст надписи черным. def activate(self): "Активизируем кнопку " self. label. set. Fill('black') self. rect. set. Width(2) self. active = True Запомните, что self ссылается на объект Button. Наш конструктор должен инициализировать self. label как подходящий объект класса Text и self. rect как объект класса Rectangle. Метод Self. active имеет также булеву переменную экземпляра, чтобы помнить активна кнопка в настоящий момент или нет. Python Programming, 2/e 87

Создание кнопок n Код метода deactivate очень похож: def deactivate(self): Создание кнопок n Код метода deactivate очень похож: def deactivate(self): "Дективизируем кнопку " self. label. set. Fill('darkgrey') self. rect. set. Width(1) self. active = 0 Python Programming, 2/e 88

Создание кнопок n n n Давайте поработаем с методом clicked. Пакет graphics содержит метод Создание кнопок n n n Давайте поработаем с методом clicked. Пакет graphics содержит метод get. Mouse, чтобы определять, где был произведён щелчок. Если приложению нужно получить щелчок мыши, то оно сначала должно вызвать метод get. Mouse, а затем посмотреть по какой кнопке щелкнули, и если щелчок был, то был ли он в окне приложения. Python Programming, 2/e 89

Создание кнопок pt = win. get. Mouse() if button 1. clicked(pt): # Делай работу Создание кнопок pt = win. get. Mouse() if button 1. clicked(pt): # Делай работу кнопки 1 elif button 2. clicked(pt): # Делай работу кнопки 1 elif button 3. clicked(pt): # Делай работу кнопки 1 … n Основная задача метода clicked определить находится ли данная точка в прямоугольнике кнопки. Python Programming, 2/e 90

Создание кнопок n n Точка находится внутри кнопки, если её координаты x и y Создание кнопок n n Точка находится внутри кнопки, если её координаты x и y находятся между крайними значениями координат x и y прямоугольника. Определить это будет легче, если у объекта класса Button содержат минимальные и максимальные значения x y как переменные экземпляра. Python Programming, 2/e 91

Создание кнопок n n def clicked(self, p): Создание кнопок n n def clicked(self, p): "ВОЗВРАЩАЕТ true если кнопка активна и p внутри“ return self. active and self. xmin <= p. get. X() <= self. xmax and self. ymin <= p. get. Y() <= self. ymax Чтобы функция возвратила True, все три части булева выражения должны быть истинны. Первая часть обеспечивает, что только активные кнопки могут возвратить сообщение что по ним щелкнули. Вторая и третья части обеспечивают, что точка, по которой щелкнули, находится в области кнопки. Python Programming, 2/e 92

Создание кнопок n Остаётся написать только конструктор: def __init__(self, win, center, width, height, label): Создание кнопок n Остаётся написать только конструктор: def __init__(self, win, center, width, height, label): """ Создаёт прямоугольную кнопку , например: qb = Button(my. Win, Point(30, 25), 20, 10, 'Quit') """ w, h = width/2. 0, height/2. 0 x, y = center. get. X(), center. get. Y() self. xmax, self. xmin = x+w, x-w self. ymax, self. ymin = y+h, y-h p 1 = Point(self. xmin, self. ymin) p 2 = Point(self. xmax, self. ymax) self. rect = Rectangle(p 1, p 2) self. rect. set. Fill('lightgray') self. rect. draw(win) self. label = Text(center, label) self. label. draw(win) self. deactivate() n Кнопки располагаются, исходя из представленных данных: центральной точки, ширины, высоты. Python Programming, 2/e 93

Создание игральных костей n n n Целью класса Die. View является графическое изображение выпавшего Создание игральных костей n n n Целью класса Die. View является графическое изображение выпавшего значения игральной кости. Лицевая сторона кости это квадрат/прямоугольник, а очки/крапинки на кости представляются кружками. Как прежде, класс Die. View будет иметь конструктор и метод. Python Programming, 2/e 94

Создание игральных костей n n конструктор – создаёт игральную кость в окне. Мы задаём Создание игральных костей n n конструктор – создаёт игральную кость в окне. Мы задаём окно, центральную точку стороны кости, We will specify the window, размер стороны, как параметры. set. Value – Изменяет вид, чтобы показать данное значение. Значение, которое нужно показать, передаётся как параметр. Python Programming, 2/e 95

Создание игральных костей n n Ясно, что труднее всего будет включить кружки на стороне Создание игральных костей n n Ясно, что труднее всего будет включить кружки на стороне кости, чтобы показать текущее значение. Одним из подходов является предварительное расположение кружков и сделать их того же цвета, что и кость. Когда кружок включается, он будет виден на стороне кости. Python Programming, 2/e 96

Создание игральных костей n n На стороне игральной кости нужно нанести 7 кружков – Создание игральных костей n n На стороне игральной кости нужно нанести 7 кружков – по колонке из трёх кружков слева и справа и один кружок в центре. Конструктор создаст фоновый квадрат и 7 кружков. Метод set. Value установит цвета кружков, исходя из выпавшего значения. Python Programming, 2/e 97

Создание игральных костей # dieview. py # Виджет для показа выпавшего значения игральной кости Создание игральных костей # dieview. py # Виджет для показа выпавшего значения игральной кости from graphics import * class Die. View: """ Класс Die. View задаёт виджет, который графически представляет стандартной шестисторонней кости. """ def __init__(self, win, center, size): """Create a view of a die, e. g. : d 1 = GDie(my. Win, Point(40, 50), 20) creates a die centered at (40, 50) having sides of length 20. """ # сначала определяем некоторые стандартные значения self. win = win self. background = "white" # цвет стороны self. foreground = "black" # цвет кружка self. psize = 0. 1 * size # радиус кружка hsize = size / 2. 0 # половина размера offset = 0. 6 * hsize # расстояние от центра до внешнего кружка Python Programming, 2/e 98

Создание игральных костей # создаём квадрат для стороны cx, cy = center. get. X(), Создание игральных костей # создаём квадрат для стороны cx, cy = center. get. X(), center. get. Y() p 1 = Point(cx-hsize, cy-hsize) p 2 = Point(cx+hsize, cy+hsize) rect = Rectangle(p 1, p 2) rect. draw(win) rect. set. Fill(self. background) # создаём self. pip 1 self. pip 2 self. pip 3 self. pip 4 self. pip 5 self. pip 6 self. pip 7 7 = = = = кружков для стандартных положений self. __make. Pip(cx-offset, cy-offset) self. __make. Pip(cx-offset, cy+offset) self. __make. Pip(cx, cy) self. __make. Pip(cx+offset, cy-offset) self. __make. Pip(cx+offset, cy+offset) self. set. Value(1) Python Programming, 2/e 99

Создание игральных костей def __make. Pip(self, x, y): Создание игральных костей def __make. Pip(self, x, y): """Внутренний метод для рисования кружка в (x, y)""" pip = Circle(Point(x, y), self. psize) pip. set. Fill(self. background) pip. set. Outline(self. background) pip. draw(self. win) return pip def set. Value(self, value): """ Установить выпавшее значение кости. """ # turn all pips off self. pip 1. set. Fill(self. background) self. pip 2. set. Fill(self. background) self. pip 3. set. Fill(self. background) self. pip 4. set. Fill(self. background) self. pip 5. set. Fill(self. background) self. pip 6. set. Fill(self. background) self. pip 7. set. Fill(self. background) Python Programming, 2/e 100

Создание игральных костей # включаем правильные кружки if value == 1: self. pip 4. Создание игральных костей # включаем правильные кружки if value == 1: self. pip 4. set. Fill(self. foreground) elif value == 2: self. pip 1. set. Fill(self. foreground) self. pip 7. set. Fill(self. foreground) elif value == 3: self. pip 1. set. Fill(self. foreground) self. pip 7. set. Fill(self. foreground) self. pip 4. set. Fill(self. foreground) elif value == 4: self. pip 1. set. Fill(self. foreground) self. pip 3. set. Fill(self. foreground) self. pip 5. set. Fill(self. foreground) self. pip 7. set. Fill(self. foreground) elif value == 5: self. pip 1. set. Fill(self. foreground) self. pip 3. set. Fill(self. foreground) self. pip 4. set. Fill(self. foreground) self. pip 5. set. Fill(self. foreground) self. pip 7. set. Fill(self. foreground) else: self. pip 1. set. Fill(self. foreground) self. pip 2. set. Fill(self. foreground) self. pip 3. set. Fill(self. foreground) self. pip 5. set. Fill(self. foreground) self. pip 6. set. Fill(self. foreground) self. pip 7. set. Fill(self. foreground) Python Programming, 2/e 101

Создание игральных костей n Полезные замечания: n n Размер закрашенного кружка должен быть 1/10 Создание игральных костей n Полезные замечания: n n Размер закрашенного кружка должен быть 1/10 размера кости, установлено методом проб и ошибок. Мы определяем и вычисляем различные атрибуты кости в конструкторе и затем используем их в других методах и функциях в классе, так что если мы захотим изменить внешний вид, то все значения и код, который идёт с ними, находятся в одном месте, а не разбросаны по всему классу. Python Programming, 2/e 102

Создание игральных костей n __make. Pip это вспомогательная функция для прорисовки каждого из 7 Создание игральных костей n __make. Pip это вспомогательная функция для прорисовки каждого из 7 кружков на стороне кости. Так как функция используется только внутри класса Die. View, её следует сделать методом класса. Её имя начинается с __, чтобы показать, что её использование «закрыто» классом и не предназначено для использования вне класса. Python Programming, 2/e 103

Основная программа # roller. py # Графическая программа для бросания пары игральных костей. Использует Основная программа # roller. py # Графическая программа для бросания пары игральных костей. Использует # специальные виджеты Button и GDie. from random import randrange from graphics import Graph. Win, Point from button import Button from dieview import Die. View def main(): # create the application window win = Graph. Win("Dice Roller") win. set. Coords(0, 0, 10) win. set. Background("green 2") # Прорисовываем интерфейсы виджетов die 1 = Die. View(win, Point(3, 7), 2) die 2 = Die. View(win, Point(7, 7), 2) roll. Button = Button(win, Point(5, 4. 5), 6, 1, " Бросаем кости") roll. Button. activate() quit. Button = Button(win, Point(5, 1), 2, 1, " Выход") Python Programming, 2/e 104

Основная программа # Event loop pt = win. get. Mouse() while not quit. Button. Основная программа # Event loop pt = win. get. Mouse() while not quit. Button. clicked(pt): if roll. Button. clicked(pt): value 1 = randrange(1, 7) die 1. set. Value(value 1) value 2 = randrange(1, 7) die 2. set. Value(value 2) quit. Button. activate() pt = win. get. Mouse() # close up shop win. close() main() Python Programming, 2/e 105

Основная программа n n n Визуальный интерфейс построен с помощью создания двух объектов класса Основная программа n n n Визуальный интерфейс построен с помощью создания двух объектов класса Die. View и двух объектов класса Button. Кнопка, осуществляющая бросание костей, первоначально активна, а кнопка «Выход» деактивирована. Это заставляет пользователя бросить кости хотя бы раз. Цикл по событиям является циклом с ограничителем, который получает щелчки мыши до тех пор, пока не щелкнут по кнопке «Выход» . Python Programming, 2/e 106

Основная программа n n Оператор if в цикле гарантирует, что кости бросаются только тогда, Основная программа n n Оператор if в цикле гарантирует, что кости бросаются только тогда, когда пользователь щелкает по кнопке «Брось кости» . Щелчок по точке, которая не содержится ни в одной кнопке заставляет цикл проделать пустую итерацию. Python Programming, 2/e 107