+ 3.1_7
This commit is contained in:
parent
98102422ec
commit
f82ed40c2a
281
mod_oop/3.1_7_course_model.py
Normal file
281
mod_oop/3.1_7_course_model.py
Normal file
@ -0,0 +1,281 @@
|
||||
"""
|
||||
https://stepik.org/lesson/701986/step/7?unit=702087
|
||||
|
||||
Необходимо создать программу для обучающего курса. Для этого объявляются три класса:
|
||||
|
||||
Course - класс, отвечающий за управление курсом в целом;
|
||||
Module - класс, описывающий один модуль (раздел) курса;
|
||||
LessonItem - класс одного занятия (урока).
|
||||
|
||||
Объекты класса LessonItem должны создаваться командой:
|
||||
lesson = LessonItem(название урока, число практических занятий, общая длительность урока)
|
||||
>>> lesson = LessonItem("название урока", 2, 10)
|
||||
|
||||
Соответственно, в каждом объекте класса LessonItem должны создаваться локальные атрибуты:
|
||||
title - название урока (строка);
|
||||
practices - число практических занятий (целое положительное число);
|
||||
duration - общая длительность урока (целое положительное число).
|
||||
|
||||
Необходимо с помощью магических методов реализовать следующую логику взаимодействия с объектами класса LessonItem:
|
||||
1. Проверять тип присваиваемых данных локальным атрибутам. Если типы не соответствуют требованиям, то генерировать исключение командой:
|
||||
raise TypeError("Неверный тип присваиваемых данных.")
|
||||
2. При обращении к несуществующим атрибутам объектов класса LessonItem возвращать значение False.
|
||||
3. Запретить удаление атрибутов title, practices и duration в объектах класса LessonItem.
|
||||
|
||||
--- тесты типов ---
|
||||
>>> LessonItem(1, 2, 10)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Неверный тип присваиваемых данных.
|
||||
>>> LessonItem("название урока", -2, 10)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Неверный тип присваиваемых данных.
|
||||
>>> LessonItem("название урока", 2, -10)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Неверный тип присваиваемых данных.
|
||||
|
||||
-------------------
|
||||
|
||||
Объекты класса Module должны создаваться командой:
|
||||
>>> module = Module("название модуля")
|
||||
|
||||
Каждый объект класса Module должен содержать локальные атрибуты:
|
||||
name - название модуля;
|
||||
lessons - список из уроков (объектов класса LessonItem), входящих в модуль (изначально список пуст).
|
||||
|
||||
Также в классе Module должны быть реализованы методы:
|
||||
add_lesson(self, lesson) - добавление в модуль (в конец списка lessons) нового урока (объекта класса LessonItem);
|
||||
remove_lesson(self, indx) - удаление урока по индексу в списке lessons.
|
||||
|
||||
Наконец, объекты класса Course создаются командой:
|
||||
course = Course(название курса)
|
||||
|
||||
И содержат следующие локальные атрибуты:
|
||||
name - название курса (строка);
|
||||
modules - список модулей в курсе (изначально список пуст).
|
||||
|
||||
Также в классе Course должны присутствовать следующие методы:
|
||||
add_module(self, module) - добавление нового модуля в конце списка modules;
|
||||
remove_module(self, indx) - удаление модуля из списка modules по индексу в этом списке.
|
||||
|
||||
Пример использования классов (в программе эти строчки не писать):
|
||||
|
||||
course = Course("Python ООП")
|
||||
module_1 = Module("Часть первая")
|
||||
module_1.add_lesson(LessonItem("Урок 1", 7, 1000))
|
||||
module_1.add_lesson(LessonItem("Урок 2", 10, 1200))
|
||||
module_1.add_lesson(LessonItem("Урок 3", 5, 800))
|
||||
course.add_module(module_1)
|
||||
module_2 = Module("Часть вторая")
|
||||
module_2.add_lesson(LessonItem("Урок 1", 7, 1000))
|
||||
module_2.add_lesson(LessonItem("Урок 2", 10, 1200))
|
||||
course.add_module(module_2)
|
||||
P.S. На экран ничего выводить не нужно.
|
||||
|
||||
>>> def make_course():
|
||||
... course = Course("Python ООП")
|
||||
... module_1 = Module("Часть первая")
|
||||
... module_1.add_lesson(LessonItem("Урок 1", 7, 1000))
|
||||
... module_1.add_lesson(LessonItem("Урок 2", 10, 1200))
|
||||
... module_1.add_lesson(LessonItem("Урок 3", 5, 800))
|
||||
... course.add_module(module_1)
|
||||
... module_2 = Module("Часть вторая")
|
||||
... module_2.add_lesson(LessonItem("Урок 1", 7, 1000))
|
||||
... module_2.add_lesson(LessonItem("Урок 2", 10, 1200))
|
||||
... course.add_module(module_2)
|
||||
... return course
|
||||
>>> ((course := make_course()).name, {
|
||||
... module.name: [
|
||||
... f"{lesson.title}, {lesson.practices}, {lesson.duration}"
|
||||
... for lesson in module.lessons
|
||||
... ]
|
||||
... for module in course.modules
|
||||
... })
|
||||
('Python ООП', {'Часть первая': ['Урок 1, 7, 1000', 'Урок 2, 10, 1200', 'Урок 3, 5, 800'], 'Часть вторая': ['Урок 1, 7, 1000', 'Урок 2, 10, 1200']})
|
||||
"""
|
||||
|
||||
|
||||
class LessonItem:
|
||||
title: str
|
||||
practices: int
|
||||
duration: int
|
||||
|
||||
class Validators:
|
||||
@staticmethod
|
||||
def is_positive(value) -> bool:
|
||||
return value > 0
|
||||
|
||||
@staticmethod
|
||||
def olways_ok(_) -> bool:
|
||||
return True
|
||||
|
||||
__nodel = "title", "practices", "duration"
|
||||
__validators = {
|
||||
"practices": Validators.is_positive,
|
||||
"duration": Validators.is_positive,
|
||||
}
|
||||
|
||||
def __init__(self, title: str, practices: int, duration: int):
|
||||
self.title, self.practices, self.duration = title, practices, duration
|
||||
|
||||
def __getattr__(self, name: str):
|
||||
return False
|
||||
|
||||
def __setattr__(self, name: str, value):
|
||||
if not (
|
||||
isinstance(value, self.__annotations__.get(name, object))
|
||||
and self.__validators.get(name, self.Validators.olways_ok)(value)
|
||||
):
|
||||
raise TypeError("Неверный тип присваиваемых данных.")
|
||||
super().__setattr__(name, value)
|
||||
|
||||
def __delattr__(self, name: str):
|
||||
if name in self.__nodel:
|
||||
raise AttributeError(f"Нельзя удалить атрибут {name}")
|
||||
|
||||
|
||||
class Module:
|
||||
def __init__(self, name: str):
|
||||
self.name, self.lessons = name, []
|
||||
|
||||
def add_lesson(self, lesson: LessonItem):
|
||||
self.lessons.append(lesson)
|
||||
|
||||
def remove_lesson(self, indx: int):
|
||||
del self.lessons[indx]
|
||||
|
||||
|
||||
class Course:
|
||||
def __init__(self, name: str):
|
||||
self.name, self.modules = name, []
|
||||
|
||||
def add_module(self, module: Module):
|
||||
self.modules.append(module)
|
||||
|
||||
def remove_module(self, indx: int):
|
||||
del self.modules[indx]
|
||||
|
||||
|
||||
def tests():
|
||||
# из коммента https://stepik.org/lesson/701986/step/7?discussion=7381286&unit=702087
|
||||
# TEST-TASK___________________________________
|
||||
course = Course("Python ООП")
|
||||
assert type(course.name) is str, "название курса должно быть строкой"
|
||||
assert (
|
||||
type(course.modules) is list and len(course.modules) == 0
|
||||
), "modules должен быть списком, изначально список пуст"
|
||||
# add_module(self, module) - добавление нового модуля в конце списка modules;
|
||||
# remove_module(self, indx) - удаление модуля из списка modules по индексу в этом списке.
|
||||
assert hasattr(course, "add_module"), "add_module необъявлен"
|
||||
assert hasattr(course, "remove_module"), "remove_module необъявлен"
|
||||
|
||||
#
|
||||
module_1 = Module("Часть первая")
|
||||
module_2 = Module("Часть вторая")
|
||||
assert type(module_1.name) is str, "название модуля должно быть строкой"
|
||||
assert (
|
||||
type(module_1.lessons) is list and len(module_1.lessons) == 0
|
||||
), "lesson должен быть списком, изначально список пуст"
|
||||
# add_lesson(self, lesson) - добавление в модуль (в конец списка lessons) нового урока (объекта класса LessonItem);
|
||||
# remove_lesson(self, indx) - удаление урока по индексу в списке lessons.
|
||||
assert hasattr(module_1, "add_lesson"), "add_lesson необъявлен"
|
||||
assert hasattr(module_1, "remove_lesson"), "remove_lesson необъявлен"
|
||||
|
||||
#
|
||||
les_1 = LessonItem("Урок 1", 7, 1000)
|
||||
les_2 = LessonItem("Урок 2", 10, 1200)
|
||||
assert type(les_1.title) is str, "название урока должно быть строкой"
|
||||
assert (
|
||||
type(les_1.practices) is int and les_1.practices > 0
|
||||
), "practices должен быть целым числом больше ноля"
|
||||
assert (
|
||||
type(les_1.duration) is int and les_1.practices > 0
|
||||
), "duration должен быть целым положительным числом"
|
||||
|
||||
#
|
||||
# проверка методов
|
||||
course.add_module(module_1)
|
||||
course.add_module(module_2)
|
||||
assert (
|
||||
len(course.modules) == 2 and course.modules[1] == module_2
|
||||
), "некоректно отработал метод add_module"
|
||||
course.remove_module(0)
|
||||
assert (
|
||||
module_1 not in course.modules and len(course.modules) == 1
|
||||
), "некоректно отработал метод remove_module"
|
||||
#
|
||||
module_1.add_lesson(les_1)
|
||||
module_1.add_lesson(les_2)
|
||||
assert (
|
||||
len(module_1.lessons) == 2 and module_1.lessons[1] == les_2
|
||||
), "некоректно отработал метод add_lesson"
|
||||
module_1.remove_lesson(0)
|
||||
assert (
|
||||
les_1 not in module_1.lessons and len(module_1.lessons) == 1
|
||||
), "некоректно отработал метод remove_lesson"
|
||||
#
|
||||
# проверка методов - LessonItem
|
||||
# 1. Проверять тип присваиваемых данных локальным атрибутам. Если типы не соответствуют требованиям, то генерировать исключение командой:
|
||||
# raise TypeError("Неверный тип присваиваемых данных.")
|
||||
try:
|
||||
les_3 = LessonItem(3, 8, 900)
|
||||
except TypeError:
|
||||
assert True
|
||||
else:
|
||||
assert (
|
||||
False
|
||||
), "не сгенерировалось исключение TypeError при записи некорректных данных в title"
|
||||
|
||||
try:
|
||||
les_3 = LessonItem("Урок 2", 8.0, 900)
|
||||
except TypeError:
|
||||
assert True
|
||||
else:
|
||||
assert (
|
||||
False
|
||||
), "не сгенерировалось исключение TypeError при записи некорректных данных в practices"
|
||||
|
||||
try:
|
||||
les_3 = LessonItem("Урок 2", 8, 900, 0)
|
||||
except TypeError:
|
||||
assert True
|
||||
else:
|
||||
assert (
|
||||
False
|
||||
), "не сгенерировалось исключение TypeError при записи некорректных данных в duration"
|
||||
|
||||
# 2. При обращении к несуществующим атрибутам объектов класса LessonItem возвращать значение False.
|
||||
les_4 = LessonItem("Урок 2", 8, 900)
|
||||
assert hasattr(
|
||||
les_1, "__getattr__"
|
||||
), "ошибка при обращении к несуществующему локальному атрибуту, метод должен вернуть False"
|
||||
assert (
|
||||
les_4.value_not_atr is False
|
||||
), "ошибка при обращении к несуществующему локальному атрибуту, метод должен вернуть False"
|
||||
# 3. Запретить удаление атрибутов title, practices и duration в объектах класса LessonItem.
|
||||
assert hasattr(
|
||||
les_4, "__delattr__"
|
||||
), "возможно вы не продумали запрет на удаление локальных атрибутов - title, practices и duration"
|
||||
try:
|
||||
del les_4.title
|
||||
del les_4.practices
|
||||
del les_4.duration
|
||||
except:
|
||||
...
|
||||
else:
|
||||
if any(
|
||||
True if _ not in les_4.__dict__ else False
|
||||
for _ in ["title", "practices", "duration"]
|
||||
):
|
||||
print(
|
||||
"Ошибка при удалении локальных атрибутов - title, practices и duration"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
tests()
|
Loading…
Reference in New Issue
Block a user