Compare commits

...

3 Commits

Author SHA1 Message Date
Dmitry Belyaev f82ed40c2a + 3.1_7 2024-04-10 12:59:16 +03:00
Dmitry Belyaev 98102422ec + 3.1.6 2024-04-10 12:06:47 +03:00
Dmitry Belyaev 6afdca0f3a add book 2024-04-10 11:14:07 +03:00
3 changed files with 469 additions and 0 deletions

65
mod_oop/3.1_5_book.py Normal file
View File

@ -0,0 +1,65 @@
"""
https://stepik.org/lesson/701986/step/5?unit=702087
Объявите класс Book для представления информации о книге. Объекты этого класса должны создаваться командами:
>>> book = Book()
>>> book = Book("название", "автор", 100, 1984) # 100 - число страниц, 1984 - год издания
В каждом объекте класса Book автоматически должны формироваться следующие локальные свойства:
title - заголовок книги (строка, по умолчанию пустая строка);
author - автор книги (строка, по умолчанию пустая строка);
pages - число страниц (целое число, по умолчанию 0);
year - год издания (целое число, по умолчанию 0).
Объявите в классе Book магический метод __setattr__ для проверки типов присваиваемых данных локальным свойствам title, author, pages и year. Если типы не соответствуют локальному атрибуту (например, title должна ссылаться на строку, а pages - на целое число), то генерировать исключение командой:
raise TypeError("Неверный тип присваиваемых данных.")
>>> book = Book(1)
Traceback (most recent call last):
...
TypeError: Неверный тип присваиваемых данных.
Создайте в программе объект book класса Book для книги:
автор: Сергей Балакирев
заголовок: Python ООП
pages: 123
year: 2022
>>> book = Book("Python ООП", "Сергей Балакирев", 123, 2022)
>>> str(book)
'Python ООП, Сергей Балакирев, 123, 2022'
"""
class Book:
title: str = ""
author: str = ""
pages: int = 0
year: int = 0
def __init__(self, *args, **kwargs):
for src in (zip(self.__annotations__, args), kwargs.items()):
for k, v in src:
setattr(self, k, v)
def __str__(self):
return f"{self.title}, {self.author}, {self.pages}, {self.year}"
def __setattr__(self, name: str, value):
if not isinstance(value, self.__annotations__.get(name, object)):
raise TypeError("Неверный тип присваиваемых данных.")
super().__setattr__(name, value)
def tests():
...
if __name__ == "__main__":
import doctest
doctest.testmod()
tests()

123
mod_oop/3.1_6_shop.py Normal file
View File

@ -0,0 +1,123 @@
"""
https://stepik.org/lesson/701986/step/6?unit=702087
Вы создаете интернет-магазин. Для этого нужно объявить два класса:
Shop - класс для управления магазином в целом;
Product - класс для представления отдельного товара.
Объекты класса Shop следует создавать командой:
>>> shop = Shop("название магазина")
В каждом объекте класса Shop должно создаваться локальное свойство:
goods - список товаров (изначально список пустой).
А также в классе объявить методы:
add_product(self, product) - добавление нового товара в магазин (в конец списка goods);
remove_product(self, product) - удаление товара product из магазина (из списка goods);
Объекты класса Product следует создавать командой:
p = Product(название, вес, цена)
>>> p = Product("название", 123, 4.56)
В них автоматически должны формироваться локальные атрибуты:
id - уникальный идентификационный номер товара (генерируется автоматически как целое положительное число от 1 и далее);
name - название товара (строка);
weight - вес товара (целое или вещественное положительное число);
price - цена (целое или вещественное положительное число).
В классе Product через магические методы (подумайте какие) осуществить проверку на тип присваиваемых данных локальным атрибутам объектов класса
(например, id - целое число, name - строка и т.п.). Если проверка не проходит, то генерировать исключение командой:
raise TypeError("Неверный тип присваиваемых данных.")
>>> Product("название", "вес", 4.56)
Traceback (most recent call last):
...
TypeError: Неверный тип присваиваемых данных.
>>> Product("название", -1, 4.56)
Traceback (most recent call last):
...
TypeError: Неверный тип присваиваемых данных.
>>> Product("название", 1, -4.56)
Traceback (most recent call last):
...
TypeError: Неверный тип присваиваемых данных.
Также в классе Product с помощью магического(их) метода(ов) запретить удаление локального атрибута id. При попытке это сделать генерировать исключение:
raise AttributeError("Атрибут id удалять запрещено.")
>>> del Product("название", 123, 4.56).id
Traceback (most recent call last):
...
AttributeError: Атрибут id удалять запрещено.
Пример использования классов (в программе эти строчки не писать):
shop = Shop("Балакирев и К")
book = Product("Python ООП", 100, 1024)
shop.add_product(book)
shop.add_product(Product("Python", 150, 512))
for p in shop.goods:
print(f"{p.name}, {p.weight}, {p.price}")
>>> shop = Shop("Балакирев и К")
>>> book = Product("Python ООП", 100, 1024)
>>> shop.add_product(book)
>>> shop.add_product(Product("Python", 150, 512))
>>> [f"{p.name}, {p.weight}, {p.price}" for p in shop.goods]
['Python ООП, 100, 1024', 'Python, 150, 512']
P.S. На экран ничего выводить не нужно.
"""
from typing import TypeAlias, Union
class Shop:
def __init__(self, name):
self.name, self.goods = name, []
def add_product(self, product):
self.goods.append(product)
def remove_product(self, product):
self.goods.remove(product)
Number: TypeAlias = Union[int, float]
class Product:
__last_id: int = 0
id: int
name: str
weight: Number
price: Number
def __new__(cls, *args, **kwargs):
cls.__last_id += 1
return super().__new__(cls)
def __init__(self, name: str, weight: Number, price: Number):
self.id = self.__last_id
self.name, self.weight, self.price = name, weight, price
def __setattr__(self, name: str, value):
typ = self.__annotations__.get(name, object)
if not isinstance(value, typ) or (typ is Number and value < 1):
raise TypeError("Неверный тип присваиваемых данных.")
super().__setattr__(name, value)
def __delattr__(self, name: str) -> None:
if name == "id":
raise AttributeError("Атрибут id удалять запрещено.")
def tests():
...
if __name__ == "__main__":
import doctest
doctest.testmod()
tests()

View 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()