Модуль 2
40,00ч

ООП и паттерны проектирования в Python

Целью изучения модуля «ООП и паттерны проектирования в Python» является формирование компетенций слушателей в области профессионального конструирования приложения в объектно-ориентированной парадигме, создания масштабируемых программ.

Задачи Модуля 2:
1) сформировать умение пользоваться структурным программированием, использовать библиотеку unittest;
2) сформировать умение создавать корректную иерархию классов, интерпретировать UML-диаграммы, выполнять рефакторинг существующего кода;
3) сформировать умение создавать Декоратор класса, создавать адаптер для интерфейса, несовместимого с системой, реализовывать паттерн Наблюдатель;
4) сформировать умение создавать цепочку обязанностей. создавать абстрактную фабрику, создавать обработчик YAML файла.
Часов в программе
8,00 часов
лекции
16,00 часов
практика
4,00 часа
самостоятельная
12,00 часов
промежуточная аттестация
40,00 часов
всего
Материально-технические условия реализации программы:
Вид занятий: Лекция
Требуемое ПО:
Zoom
Браузер Chrome
Microsoft Visual Studio 2010 или выше
Вид занятий: Практическая работа
Требуемое ПО:
Zoom
Браузер Chrome
Microsoft Visual Studio 2010 или выше
Вид занятий: Промежуточная (итоговая) аттестация
Требуемое ПО:
Zoom
Браузер Chrome
Microsoft Visual Studio 2010 или выше
Информационные ресуры
Документация Postgres про сравнение строк - https://postgrespro.ru/docs/postgrespro/9.5/functions-matching
Документация Postgres про другие функции работы со строками - https://postgrespro.ru/docs/postgrespro/9.5/functions-string
Тестер регулярных выражений - https://www.regextester.com
Интерактивный учебник по SQL -http://www.sql-tutorial.ru/ru/content.html
Введение в анализ данных с помощью Pandas - https://habr.com/ru/post/196980/
Начало работы с Power BI - https://docs.microsoft.com/ru-ru/power-bi/fundamentals/desktop-getting-started
Образовательные ресуры
https://www.coursera.org/learn/oop-patterns-python/home/welcome

Учебно-методические материалы

Методы, формы и технологии

Методы обучения:
- лекция;
- практическая работа под руководством учителя;
- самостоятельная практическая работа;
- изучение литературы по теме.
Методы контроля:
- выполнение практических занятий по темам лекций;
- выполнение итогового задания.
Формы организации учебных занятий:
- лекция;
- вебинар с элементами практической работы и разбора теоретического материала.
Формы организации учебной деятельности:
- групповая работа;
- индивидуальная работа.
Дистанционные образовательные технологии:
- использование образовательных интернет-ресурсов;
- использование ресурсов, созданных преподавателем (ноутбуки для решения задач по программированию);
- WEB-консультации и другие.

Методические разработки

Задание для промежуточной (итоговой) аттестации
Проект
Проект предполагает очную защиту перед экзаменационной комиссией. Перед комиссией студент готовит материалы согласно заданию и направляет экзаменационной комиссии не менее чем за 2 дня до назначенной даты экзамена
В данном задании необходимо будет закончить разработку полноценной ролевой игры «Рыцарь в подземелье». В данной игре необходимо будет играть за рыцаря, который путешествует по многоэтажному подземелью, борется с врагами и собирает сокровища.
Вам будет дан код движка игры, текстуры и игровая логика. Некоторые из классов и методов изначально не реализованы в предоставленном коде. Их и необходимо будет реализовать в данном задании. В помощь вам будут даны полные диаграммы классов, которые должны быть представлены в проекте.
Кроме реализации новых методов, необходимо будет дописать недостающий код в некоторые из существующих функций и методов. Места, в которых требуется исправление, помечены меткой #FIXME.
Кроме основных заданий, Вам будут предложены дополнительные задания. В них вам нужно будет немного усовершенствовать игру. При выполнении дополнительных заданий старайтесь быть креативными.
В качестве ответа вам необходимо будет прикрепить архив, содержащий всю структуру папок Вашего проекта.

Материалы курса

Примеры заданий по модулю 2
Практические задания

Тема 1. Тестирование и отладка программ
Дана функция factorize(x) со следующим контрактом:

def factorize(x):
"""
Factorize positive integer and return its factors.
:type x: int,>=0
:rtype: tuple[N],N>0
"""
pass

Необходимо написать комплект тестов используя модуль unittest стандартной библиотеки Python. Имя тестового класса - TestFactorize.
Описание тестов:
test_wrong_types_raise_exception - проверяет, что передаваемый в функцию аргумент типа float или str вызывает исключение TypeError. Тестовый набор входных данных: 'string', 1.5
test_negative - проверяет, что передача в функцию factorize отрицательного числа вызывает исключение ValueError. Тестовый набор входных данных: -1, -10, -100
test_zero_and_one_cases - проверяет, что при передаче в функцию целых чисел 0 и 1, возвращаются соответственно кортежи (0,) и (1,). Набор тестовых данных: 0 → (0, ), 1 → (1, )
test_simple_numbers - что для простых чисел возвращается кортеж, содержащий одно данное число. Набор тестовых данных: 3 → (3, ), 13 → (13, ), 29 → (29, )
test_two_simple_multipliers — проверяет случаи, когда передаются числа для которых функция factorize возвращает кортеж с числом элементов равным 2. Набор тестовых данных: 6 → (2, 3), 26 → (2, 13), 121 --> (11, 11)
test_many_multipliers - проверяет случаи, когда передаются числа для которых функция factorize возвращает кортеж с числом элементов больше 2. Набор тестовых данных: 1001 → (7, 11, 13) , 9699690 → (2, 3, 5, 7, 11, 13, 17, 19)
ВАЖНО! Все входные данные должны быть такими, как указано в условии. Название переменной в каждом тестовом случае должно быть именно "x". При этом несколько различных проверок в рамках одного теста должны быть обработаны как подслучаи с указанием x: subTest(x=...). В задании необходимо реализовать ТОЛЬКО класс TestFactorize, кроме этого реализовывать ничего не нужно. Импортировать unittest и вызывать unittest.main() в решении также не нужно.

Тема 2. Объектно-ориентированное проектирование
Даны 3 класса A, B, C, имеющие сходный (но не одинаковый) интерфейс. Вам необходимо создать абстрактный базовый класс Base и построить корректную схему наследования.
При выполнении следует избегать дублирования кода, и стараться следовать SOLID принципам ООП.
Кроме того, рекомендуется самостоятельно тестировать код перед отправкой, а также при написании следовать стандарту PEP 8.

import math

class Base:

pass

class A:
def __init__(self, data, result):
self.data = data
self.result = result

def get_answer(self):
return [int(x >= 0.5) for x in self.data]

def get_score(self):
ans = self.get_answer()
return sum([int(x == y) for (x, y) in zip(ans, self.result)]) \
/ len(ans)

def get_loss(self):
return sum(
[(x - y) * (x - y) for (x, y) in zip(self.data, self.result)])

class B:
def __init__(self, data, result):
self.data = data
self.result = result

def get_answer(self):
return [int(x >= 0.5) for x in self.data]

def get_loss(self):
return -sum([
y * math.log(x) + (1 - y) * math.log(1 - x)
for (x, y) in zip(self.data, self.result)
])

def get_pre(self):
ans = self.get_answer()
res = [int(x == 1 and y == 1) for (x, y) in zip(ans, self.result)]
return sum(res) / sum(ans)

def get_rec(self):
ans = self.get_answer()
res = [int(x == 1 and y == 1) for (x, y) in zip(ans, self.result)]
return sum(res) / sum(self.result)

def get_score(self):
pre = self.get_pre()
rec = self.get_rec()
return 2 * pre * rec / (pre + rec)

class C:
def __init__(self, data, result):
self.data = data
self.result = result

def get_answer(self):
return [int(x >= 0.5) for x in self.data]

def get_score(self):
ans = self.get_answer()
return sum([int(x == y) for (x, y) in zip(ans, self.result)]) \
/ len(ans)

def get_loss(self):
return sum([abs(x - y) for (x, y) in zip(self.data, self.result)])

Тема 3. Паттерны проектирования (часть 1)
Необходимо написать реализацию системы эффектов игры в стиле фэнтези, которые могут быть наложены на героя игры.
В игре есть герой, который обладает некоторым набором характеристик. Класс героя описан следующим образом:

class Hero:
def __init__(self):
self.positive_effects = []
self.negative_effects = []
self.stats = {
"HP": 128, # health points
"MP": 42, # magic points,
"SP": 100, # skill points
"Strength": 15, # сила
"Perception": 4, # восприятие
"Endurance": 8, # выносливость
"Charisma": 2, # харизма
"Intelligence": 3, # интеллект
"Agility": 8, # ловкость
"Luck": 1 # удача
}

def get_positive_effects(self):
return self.positive_effects.copy()

def get_negative_effects(self):
return self.negative_effects.copy()

def get_stats(self):
return self.stats.copy()

К основным характеристикам относятся: Сила (Strength), Восприятие (Perception), Выносливость (Endurance), Харизма (Charisma), Интеллект (Intelligence), Ловкость (Agility), Удача (Luck).
Враги и союзники могут накладывать на героя положительные и отрицательные эффекты. Эти эффекты изменяют характеристики героя, увеличивая или уменьшая значения определенных характеристик, в зависимости от того какие эффекты были наложены. На героя можно накладывать бесконечно много эффектов, действие одинаковых эффектов суммируется. Игрок должен знать, какие положительные и какие отрицательные эффекты на него были наложены и в каком порядке. Названия эффектов совпадают с названиями классов.
За получение данных о текущем состоянии героя отвечают методы get_stats, get_positive_effects, get_negative_effects.
Вам необходимо написать систему декораторов, представленную на UML-диаграмме:

Описание эффектов:
Берсерк (Berserk)
Увеличивает характеристики: Сила, Выносливость, Ловкость, Удача на 7;
уменьшает характеристики: Восприятие, Харизма, Интеллект на 3;
количество единиц здоровья увеличивается на 50.
Благословение (Blessing)
увеличивает все основные характеристики на 2.
Слабость (Weakness)
уменьшает характеристики: Сила, Выносливость, Ловкость на 4.
Сглаз (EvilEye)
уменьшает характеристику Удача на 10.
Проклятье (Curse)
уменьшает все основные характеристики на 2.

При выполнении задания необходимо учитывать, что:
изначальные характеристики базового объекта не должны меняться.
изменения характеристик и накладываемых эффектов (баффов/дебаффов) должны происходить динамически, то есть вычисляться при вызове методов get_stats, get_positive_effects, get_negative_effects
абстрактные классы AbstractPositive, AbstractNegative и соответственно их потомки могут принимать любой параметр base при инициализации объекта (_ _ init _ _ (self, base))
эффекты должны корректно сниматься, в том числе и из середины стека
Для тестирования правильности работы вашего решения вы можете повторить пример работы, приведенный ниже, или использовать тестовый скрипт. Заметим, что данные примеры не покрывают всех тестовых случаев, проверяемых тестовой системой, это всего лишь отправная точка для ваших экспериментов с кодом решения.
Важно! На проверку необходимо сдать фрагмент кода, содержащий только реализацию 8 классов: AbstractEffect, AbstractPositive, AbstractNegative, Berserk, Blessing, Weakness, Curse, EvilEye. Описывать класс Hero и импортировать его в коде НЕ НУЖНО (он уже реализован и будет импортирован тестовой системой).
Пример работы:

>>> from deco import *
>>> # создаем героя
>>> hero = Hero()
>>> hero.get_stats()
{'HP': 128, 'MP': 42, 'SP': 100, 'Strength': 15, 'Perception': 4, 'Endurance': 8, 'Charisma': 2, 'Intelligence': 3, 'Agility': 8, 'Luck': 1}
>>> hero.stats
{'HP': 128, 'MP': 42, 'SP': 100, 'Strength': 15, 'Perception': 4, 'Endurance': 8, 'Charisma': 2, 'Intelligence': 3, 'Agility': 8, 'Luck': 1}
>>> hero.get_negative_effects()
[ ]
>>> hero.get_positive_effects()
[ ]
>>> # накладываем эффект

>>> brs1 = Berserk(hero)
>>> brs1.get_stats()
{'HP': 178, 'MP': 42, 'SP': 100, 'Strength': 22, 'Perception': 1, 'Endurance': 15, 'Charisma': -1, 'Intelligence': 0, 'Agility': 15, 'Luck': 8}
>>> brs1.get_negative_effects()
[ ]
>>> brs1.get_positive_effects()
['Berserk']

>>> # накладываем эффекты
>>> brs2 = Berserk(brs1)

>>> cur1 = Curse(brs2)

>>> cur1.get_stats()
{'HP': 228, 'MP': 42, 'SP': 100, 'Strength': 27, 'Perception': -4, 'Endurance': 20, 'Charisma': -6, 'Intelligence': -5, 'Agility': 20, 'Luck': 13}
>>> cur1.get_positive_effects()
['Berserk', 'Berserk']
>>> cur1.get_negative_effects()
['Curse']
>>> # снимаем эффект Berserk
>>> cur1.base = brs1
>>> cur1.get_stats()
{'HP': 178, 'MP': 42, 'SP': 100, 'Strength': 20, 'Perception': -1, 'Endurance': 13, 'Charisma': -3, 'Intelligence': -2, 'Agility': 13, 'Luck': 6}
>>> cur1.get_positive_effects()
['Berserk']
>>> cur1.get_negative_effects()
['Curse']

>>>

Тема 4. Паттерны проектирования (часть 2)
Вам дан объект класса SomeObject, содержащего три поля: integer_field, float_field и string_field:

class SomeObject:
def __init__(self):
self.integer_field = 0
self.float_field = 0.0
self.string_field = ""

Необходимо реализовать поведение:
 EventGet(<type>) создаёт событие получения данных соответствующего типа
 EventSet(<value>) создаёт событие изменения поля типа type(<value>)
Необходимо реализовать классы NullHandler, IntHandler, FloatHandler, StrHandler так, чтобы можно было создать цепочку:

chain = IntHandler(FloatHandler(StrHandler(NullHandler)))

Описание работы цепочки:
 chain.handle(obj, EventGet(int)) — вернуть значение obj.integer_field
 chain.handle(obj, EventGet(str)) — вернуть значение obj.string_field
 chain.handle(obj, EventGet(float)) — вернуть значение obj.float_field
 chain.handle(obj, EventSet(1)) — установить значение obj.integer_field =1
 chain.handle(obj, EventSet(1.1)) — установить значение obj.float_field = 1.1
 chain.handle(obj, EventSet("str")) — установить значение obj.string_field = "str"


Пример работы:
>>> obj = SomeObject()
>>> obj.integer_field = 42
>>> obj.float_field = 3.14
>>> obj.string_field = "some text"
>>> chain = IntHandler(FloatHandler(StrHandler(NullHandler)))
>>> chain.handle(obj, EventGet(int))
42
>>> chain.handle(obj, EventGet(float))
3.14
>>> chain.handle(obj, EventGet(str))
'some text'
>>> chain.handle(obj, EventSet(100))
>>> chain.handle(obj, EventGet(int))
100
>>> chain.handle(obj, EventSet(0.5))
>>> chain.handle(obj, EventGet(float))
0.5
>>> chain.handle(obj, EventSet('new text'))
>>> chain.handle(obj, EventGet(str))
'new text'

Учебная литература

Основная литература:
Think Python [Электронный ресурс] – Режим доступа - https://greenteapress.com/wp/think-python-2e/
Automate the Boring Stuff with Python [Электронный ресурс] – Режим доступа - https://automatetheboringstuff.com/
Dive Into Python 3 [Электронный ресурс] – Режим доступа -http://diveintopython3.problemsolving.io/
Problem Solving with Algorithms and Data Structures using Python [Электронный ресурс] – Режим доступа -https://runestone.academy/runestone/static/pythonds/index.html
Swaroop Chitlur. A Byte of Python [Электронный ресурс] – Режим доступа - https://wombat.org.ua/AByteOfPython/AByteofPythonRussian-2.02.pdf – 2020.
Федоров Д. Основы программирования на примере языка Python [Текст] : учебное пособие / Д. Федоров. - 2018.
Свейгарт Э. Автоматизация рутинных задач с помощью Python [Текст] : практическое руководство для начинающих / Эл Свейгарт. – 2017.

Дополнительная литература:
Маккинни У. Python и анализ данных [Текст] / У. Маккинни. – 2015.

Перечень учебно-методического обеспечения для самостоятельной работы обучающихся по дисциплине (модулю)
Бэрри П. Изучаем программирование на Python [Текст] / П. Бэрри. – 2017.
Савельев В. Статистика и котики [Текст] / Владимир Савельев. – 2018.
Бослав С. Статистика для всех [Текст] / Сара Бослав. – 2015.
Хамидуллин Р. Я. Теория вероятностей и математическая статистика [Текст] / Р.Я. Хамидуллин. – 2020.
Справочник по функциям DAX [Электронный ресурс] – Режим доступа - https://docs.microsoft.com/ru-ru/dax/dax-function-reference
Талер Р. Nudge. Архитектура выбора [Текст] / Ричард Талер. – 2017.
Желязны Дж. Говори на языке диаграмм [Текст] : пособие по визуальным коммуникациям / Джин Желязны. – 2020.

Перечень ресурсов информационно-телекоммуникационной сети "Интернет", необходимых для освоения дисциплины (модуля)
Документация Postgres про сравнение строк - https://postgrespro.ru/docs/postgrespro/9.5/functions-matching
Документация Postgres про другие функции работы со строками - https://postgrespro.ru/docs/postgrespro/9.5/functions-string
Тестер регулярных выражений - https://www.regextester.com
Интерактивный учебник по SQL -http://www.sql-tutorial.ru/ru/content.html
Введение в анализ данных с помощью Pandas - https://habr.com/ru/post/196980/
Начало работы с Power BI - https://docs.microsoft.com/ru-ru/power-bi/fundamentals/desktop-getting-started

Темы

Тестирование и отладка программ Объектно-ориентированное проектирование Паттерны проектирования (часть 1) Паттерны проектирования (часть 2)
Лекции
2,00ч
Практические занятия
4,00ч
Самостоятельная работа
1,00ч
Всего
7,00ч
Лекции
2,00ч
Практические занятия
4,00ч
Самостоятельная работа
1,00ч
Всего
7,00ч
Лекции
2,00ч
Практические занятия
4,00ч
Самостоятельная работа
1,00ч
Всего
7,00ч
Лекции
2,00ч
Практические занятия
4,00ч
Самостоятельная работа
1,00ч
Всего
7,00ч
Промежуточная аттестация 12,00 часов
Зачет