Введение в ООП; классы; инкапсуляция
Не успели в 7 день
itertools
Построение графиков в PyGame
- нарисуем ломаную
pygame.draw.lines()
например, график функции y = sqrt(x) или y = sin(x)
график 1:1px очень мелкий; особенно забавным получается sin(x)
- нужно прибегать к масштабированию и смещению осей, т. е. экранных координат
Напишем функцию scale(x,a,b,A,B), которая по числу x на отрезке a…b вычисляет число X на отрезке A…B, делящее этот отрезок в той же пропорции
(подсказка) scale(a,a,b,A,B) == A, scale(b,a,b,A,B) == B, scale((a+b)/2,a,b,A,B) == (A+B)/2
- (спойлер!) вычесть начало старого отрезка (получится что-то от 0), поделить на длину отрезка (получится что-то от 0 до 1), умножить на длину нового отрезка, прибавить его начало
Нарисовать sin(x) на отрезке a≤x≤b, 100 точек в графике, график растянут на всё окно
1 # Ввести A и B, 2 # Нарисовать график функции sin(x), 3 # где A≤x≤B, 100 точек в графике 4 # график должен помещаться во всё окно 5 6 import pygame 7 from math import * 8 9 W, H = 320,200 10 N = 100 11 12 pygame.init() 13 14 screen = pygame.display.set_mode((W,H)) 15 A, B = -3, 4 16 X = [A+(B-A)*i/(N-1) for i in range(N)] 17 Dots = [(x,sin(x)) for x in X] 18 Graph = [ ((x-A)*W/(B-A), (y+1)*H/2) for x,y in Dots] 19 pygame.draw.lines(screen, (255,255,0,255), False, Graph) 20 21 while pygame.event.wait().type != pygame.QUIT: 22 pygame.display.flip()
Переписать предыдущее задание с использованием масштабирующей функции scale
Попробовать при помощи scale уместить график в прямоугольник заданных размеров
1 # переписать программу рисования синуса 2 # с использованием функции масштабирования 3 # scale(x,a,b,A,B), которая x из диапазона a…b превращает 4 # в X из диапазона A…B 5 # уместить график в заданный прямогугольник 6 7 import pygame 8 from math import * 9 10 def scale(x,a,b,A,B): 11 return (x-a)*(B-A)/(b-a)+A 12 13 W, H = 320,200 14 N = 100 15 Grect = pygame.Rect(10,5,W-20,H-10) 16 pygame.init() 17 18 screen = pygame.display.set_mode((W,H)) 19 A, B = -3, 4 20 X = [scale(i,0,N-1,A,B) for i in range(N)] 21 Dots = [(x,sin(x)) for x in X] 22 Graph = [(scale(x,A,B,Grect.left,Grect.right), scale(y,-1,1,Grect.top,Grect.bottom)) for x,y in Dots] 23 pygame.draw.lines(screen, (255,255,0,255), False, Graph) 24 25 while pygame.event.wait().type != pygame.QUIT: 26 pygame.display.flip()
К зачёту: Поправить пример:
- добавить возможность таскать график мышью
- добавить масштабирование колесом
- нарисовать оси координат
оси координат должны всегда быть видны
Классы
Можно почитать скетч про классы в Python3
класс по имени someclass — это тоже такой объект
callable(someclass) == True
(type(some) is type) == True"
- ...такой объект с полями
aka static class members в других языках
класс можно инстанциировать — создать экземпляр класса, объект класса
a = someclass()
(type(a)) is someclass) == True
- такой объект — не что иное, как пространство имён
- TODO вспомним: а чем отличается от словаря?
- к объекту можно добавлять поля, которых класс изначально не предусматривал
при обращении к callable-полям класса через объект мы получаем не само поле, а обёртку над ним, имеющую тип method:
def ff(...): ...
some.fn = ff
type(some.fn) is type(ff) == True
type(a.fn) is type(ff) == False
вызов метода a.fn(*args) аналогичен вызову функции-поля класса some.fn(a, *args)
Некоторые методы и поля (вида __blabla__) имеют особенное значение
__init__(), aka конструктор
__class__ — тип объекта; класс, экземпляром которого он является
__str__() — преобразование в строку
__eq__() — операция сравнения (==)
'запись на Python' a == 2 'эквивалентна записи' a.__eq__(2)
__add__() — операция сложения
естественно, их можно переопределять (перегружать)
- тем самым наделять различные конструкции языка смыслом
например, def __eq__(self, ob): ...
- левые/правые операции
если a.__add__(b) возвращает NotImplemented, то Python пытается подставить b.__radd__(a)
создать cписок из 10 экземпляров класса Square:
содержащего docstring, описывающий, что такое объект класса Square
содержащего pygame.Rect
с методом show(self, surface), рисующим квадрат на surface
с методом ID(self), выдающим строку с описанием объекта
содержащего информацию о цвете (pygame.Color)
- задать каждому координаты, размер, цвет
- нарисовать, пользуясь методами класса
1 # создать класс Square, который должен 2 # - содержать размер и координатвы (pygame.Rect) 3 # - содержать цвет (pygame.Color) 4 # - содержать метод show(self, surface) — нарисовать себя на surface 5 # - содержать метод ID(self) — строка с описанием объекта 6 # создать список из 10 таких прямоугольников, задать их координаты, размер и цвет 7 # нарисовать все 8 9 import pygame 10 import random 11 12 def randcolor(): 13 col = [random.randrange(100,255),random.randrange(0,255),random.randrange(0,100)] 14 random.shuffle(col) 15 return pygame.Color(*col) 16 17 class Square: 18 rect = pygame.Rect(0,0,0,0) 19 color = pygame.Color(0,0,0,0) 20 21 def show(self, surface): 22 pygame.draw.rect(surface, self.color, self.rect) 23 24 def ID(self): 25 return "Square: {}/{}".format(self.rect, self.color) 26 27 W, H = 320, 200 28 pygame.init() 29 screen = pygame.display.set_mode((W, H)) 30 31 SQS = [Square() for i in range(10)] 32 for s in SQS: 33 s.color = randcolor() 34 s.rect = pygame.Rect(random.randrange(0, W-10), random.randrange(0, H-10), 10, 10) 35 36 for s in SQS: 37 s.show(screen) 38 39 while pygame.event.wait().type != pygame.QUIT: 40 pygame.display.flip()
реализовать класс Rect как Square:
поддержка сложения, ( вычитания, умножения на число)
pygame.Rect сами собой не складываются, надо выдумать для них сложение (например, результат — прямоугольник суммарного размера по координатам первого слагаемого)
pygame.Color при сложении довольно быстро дают белый, интереснее брать полусумму цветов (примерно так: self.color//pygame.Color(2,2,2,1)+other.color//pygame.Color(2,2,2,1))
при этом вместо двух старых образуется один новый, пока не останется один
- отображение на экран
К зачёту: программа, которая умеет рисовать такие прямоугольники, таскать их по экрану и при переносе одного прямоугольника на другой складывает их