diff --git a/homeworks/les08/task01.py b/homeworks/les08/task01.py new file mode 100644 index 0000000..e2428ab --- /dev/null +++ b/homeworks/les08/task01.py @@ -0,0 +1,127 @@ +"""1. Реализовать класс «Дата», функция-конструктор которого должна принимать дату в виде строки формата +«день-месяц-год». В рамках класса реализовать два метода. +Первый, с декоратором @classmethod, должен извлекать число, месяц, год и преобразовывать их тип к типу «Число». +Второй, с декоратором @staticmethod, должен проводить валидацию числа, месяца и года (например, месяц — от 1 до 12). +Проверить работу полученной структуры на реальных данных. """ + + +class MyDate: + _year = 0 + _month = 0 + _day = 0 + __months = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + is_leap = None + + def __init__(self, str_date: str): + """ + принимает дату в виде строки формата «день-месяц-год». + :param str_date: + """ + + self._build_date(str_date) + if MyDate._is_ok_year(self._year): + self.is_leap = MyDate.is_leap_year(self._year) + else: + raise ValueError('My date structure (year) is incorrect') + if not MyDate.check_date(self._day, self._month, self._year): + raise ValueError('The data for date is not allowed') + + @staticmethod + def is_leap_year(year): + """ + 1. Если год делится на 4 без остатка, перейдите на шаг 2. + В противном случае перейдите к выполнению действия 5. + 2. Если год делится на 100 без остатка, перейдите на шаг 3. + В противном случае перейдите к выполнению действия 4. + 3. Если год делится на 400 без остатка, перейдите на шаг 4. + В противном случае перейдите к выполнению действия 5. + 4. Год високосный (366 дней). + 5. Год не високосный год (365 дней). + https://docs.microsoft.com/ru-ru/office/troubleshoot/excel/determine-a-leap-year + :return: + """ + if not year % 4: # 1 + if not year % 100: # 2 + if not year % 400: + return True + else: + return False + else: + return True + else: # 5 + return False + + @classmethod + def set_date(cls, str_date: str): + """ + Извлекает число, месяц, год и возвращает объект с данными типа int + :param str_date: + :return: + """ + return cls(str_date) + + @staticmethod + def check_date(date, month, year, verbose=False): + """ + Проверяет детально дату включая максимальную дату месяца с учетом високосных лет + :param date: + :param month: + :param year: + :param verbose: + :return: + """ + is_ok = False + if verbose: + print(f'{date} - {month} - {year}') + if 1 <= month <= 12: + is_ok = True + elif verbose: + print('the month is wrong number') + if is_ok: + is_ok = date <= MyDate.__months[month + 1] + if not is_ok and verbose: + print('the day is wrong number of month') + if is_ok: + is_ok = MyDate._is_ok_year(year) + if not is_ok and verbose: + print('the year is not belong to correct period') + if is_ok and month == 2: + is_ok = not MyDate.is_leap_year(year) and date <= 28 + if not is_ok and verbose: + print('the day of Feb is wrong') + if verbose: + print(f' date is {"ok" if is_ok else "wrong"}') + return is_ok + + @staticmethod + def _is_ok_year(year): + # мои правила проверки года + return 1970 <= year <= 2060 + + def _build_date(self, str_date): + # принимает дату в виде строки формата «день-месяц-год». + self._day, self._month, self._year = tuple(map(int, str_date.split('-'))) + + @property + def day(self): + return self._day + + @property + def month(self): + return self._month + + @property + def year(self): + return self._year + + +if __name__ == '__main__': + d1 = MyDate.check_date(13, 2, 1977, verbose=True) + d2 = MyDate.check_date(13, 2, 1967, verbose=True) + d3 = MyDate.check_date(30, 2, 1977, verbose=True) + d4 = MyDate.check_date(29, 2, 2000, verbose=True) + + D1 = MyDate.set_date('13-02-1977') + print(f'D1: {D1.day} {D1.month} {D1.year}') + D2 = MyDate('13-02-1977') + print(f'D2: {D2.day} {D2.month} {D2.year}') diff --git a/homeworks/les08/task02.py b/homeworks/les08/task02.py new file mode 100644 index 0000000..6b2e443 --- /dev/null +++ b/homeworks/les08/task02.py @@ -0,0 +1,26 @@ +"""2. Создайте собственный класс-исключение, обрабатывающий ситуацию деления на нуль. Проверьте его работу на данных, +вводимых пользователем. При вводе пользователем нуля в качестве делителя программа должна корректно обработать эту +ситуацию и не завершиться с ошибкой. """ + + +class MyZeroDivisionError(Exception): + def __init__(self, message='Ошибка: Делитель = 0'): + self.message = message + + def __str__(self): + return self.message + + +if __name__ == '__main__': + while True: + buf = input('Введите 1 число :') + if buf == '': + break + d1 = int(buf) + d2 = int(input('Введите 2 число :')) + try: + if d2 == 0: + raise MyZeroDivisionError('Ошибка: Делитель = 0') + print(d1 / d2) + except MyZeroDivisionError as e: + print(e) diff --git a/homeworks/les08/task03.py b/homeworks/les08/task03.py new file mode 100644 index 0000000..417b497 --- /dev/null +++ b/homeworks/les08/task03.py @@ -0,0 +1,32 @@ +"""3. Создайте собственный класс-исключение, который должен проверять содержимое списка на наличие только чисел. +Проверить работу исключения на реальном примере. Необходимо запрашивать у пользователя данные и заполнять список. +Класс-исключение должен контролировать типы данных элементов списка. Примечание: длина списка не фиксирована. +Элементы запрашиваются бесконечно, пока пользователь сам не остановит работу скрипта, введя, например, +команду “stop”. При этом скрипт завершается, сформированный список выводится на экран. Подсказка: для данного задания +примем, что пользователь может вводить только числа и строки. При вводе пользователем очередного элемента необходимо +реализовать проверку типа элемента и вносить его в список, только если введено число. Класс-исключение должен не +позволить пользователю ввести текст (не число) и отобразить соответствующее сообщение. При этом работа скрипта не +должна завершаться. """ + + +class MyOnlyIntError(Exception): + def __init__(self, message='Ошибка: должно быть число'): + self.message = message + + def __str__(self): + return self.message + + +if __name__ == '__main__': + int_list = [] + while True: + buf = input('Введите данные:') + if buf == 'stop': + break + try: + if not buf.isdigit(): + raise MyOnlyIntError + int_list.append(int(buf)) + except MyOnlyIntError as e: + print(e) + print(int_list) diff --git a/homeworks/les08/task04.py b/homeworks/les08/task04.py new file mode 100644 index 0000000..87b476c --- /dev/null +++ b/homeworks/les08/task04.py @@ -0,0 +1,32 @@ +"""4. Начните работу над проектом «Склад оргтехники». Создайте класс, описывающий склад. А также класс «Оргтехника», +который будет базовым для классов-наследников. Эти классы — конкретные типы оргтехники (принтер, сканер, ксерокс). В +базовом классе определить параметры, общие для приведенных типов. В классах-наследниках реализовать параметры, +уникальные для каждого типа оргтехники. """ + + +class WarehouseEquipments: + shelf = {} + + def __init__(self, shelf): + self.shelf = shelf + + +class OfficeEquipment: + inventory_number = 0 + dimensions = (0, 0) + weight = 0 + place = (0, 0) + is_network = False + + +class Printer(OfficeEquipment): + letter_size = '' + color = False + + +class CopyMachine(OfficeEquipment): + auto_feeder = False + + +class Scanner(OfficeEquipment): + is_pdf_ready = False diff --git a/homeworks/les08/task05.py b/homeworks/les08/task05.py new file mode 100644 index 0000000..e588c95 --- /dev/null +++ b/homeworks/les08/task05.py @@ -0,0 +1,104 @@ +"""5. Продолжить работу над первым заданием. Разработать методы, отвечающие за приём оргтехники на склад и передачу в +определенное подразделение компании. Для хранения данных о наименовании и количестве единиц оргтехники, +а также других данных, можно использовать любую подходящую структуру, например словарь. """ + + +class WarehouseEquipments: + shelf = {} + in_work = {} + __current_num = 1000 + + def __init__(self, shelf=None): + self.take_storage_equipments(shelf) + + def take_storage_equipments(self, equipments): + for machine in equipments: + self.take_storage(machine) + + def take_storage(self, equipment): + if isinstance(equipment, OfficeEquipment): + for _ in range(equipment.number): + self.__current_num += 1 + equipment.inventory_number = self.__current_num + self.shelf[self.__current_num] = equipment + + def find_by_inventory(self, number): + return self.shelf[number] + + def move_in_work(self, inventory, division): + self.in_work[inventory] = (self.shelf[inventory], division) + del (self.shelf[inventory]) + + def move_in_shelf(self, inventory): + self.shelf[inventory], _ = self.in_work[inventory] + del (self.in_work[inventory]) + + def print_shelf(self): + for inventory, equipment in self.shelf.items(): + print(f'{inventory} {equipment.type} {equipment.brand} {equipment.model}') + + def print_in_work(self): + for inventory, (equipment, division) in self.in_work.items(): + print(f'{inventory} {equipment.type} {equipment.brand} {equipment.model} {division}') + + +class OfficeEquipment: + brand = '' + model = '' + inventory_number = 0 + dimensions = (0, 0) + weight = 0 + place = (0, 0) + is_network = False + number = 0 + + def __init__(self, brand, model, number=1): + self.brand = brand + self.model = model + self.number = number + + +class Printer(OfficeEquipment): + type = 'Принтер' + letter_size = '' + color = False + + +class CopyMachine(OfficeEquipment): + type = 'Копир' + auto_feeder = False + + +class Scanner(OfficeEquipment): + type = 'Сканер' + is_pdf_ready = False + + +if __name__ == '__main__': + sc_1 = Scanner('Canon', 'CanoScan LiDE 400') + sc_2 = Scanner('Epson', 'Perfection V19') + sc_3 = Scanner('Panasonic', 'KV-SL1066') + pr_1 = Printer('Xerox', 'Phaser 3020BI') + pr_2 = Printer('HP', 'LaserJet Pro M15w') + pr_3 = Printer('Brother', 'HL-L2340DWR') + cp_1 = CopyMachine('Xerox', 'B1022') + cp_2 = CopyMachine('Xerox', 'B215') + cp_3 = CopyMachine('Konica-Minolta', 'A0XY026') + wh1 = WarehouseEquipments([sc_1, sc_2, sc_3, pr_1, pr_2, pr_3]) + print('Склад создан') + wh1.print_shelf() + print('Добавлено оборудование') + wh1.take_storage_equipments([cp_1, cp_2, cp_3]) + wh1.print_shelf() + print('Выдано оборудование') + wh1.move_in_work(1005, 'Secretary') + wh1.move_in_work(1006, 'Secretary') + wh1.move_in_work(1007, 'R&D') + wh1.print_in_work() + print('Возвращено оборудование') + wh1.move_in_shelf(1005) + wh1.move_in_shelf(1006) + print('Склад') + wh1.print_shelf() + print('Выдано') + wh1.print_in_work() diff --git a/homeworks/les08/task06.py b/homeworks/les08/task06.py new file mode 100644 index 0000000..5084094 --- /dev/null +++ b/homeworks/les08/task06.py @@ -0,0 +1,224 @@ +"""6. Продолжить работу над вторым заданием. Реализуйте механизм валидации вводимых пользователем данных. Например, +для указания количества принтеров, отправленных на склад, нельзя использовать строковый тип данных. Подсказка: +постарайтесь по возможности реализовать в проекте «Склад оргтехники» максимум возможностей, изученных на уроках по ООП. +""" +import datetime + + +class WarehouseEquipments: + """ Класс реализации склада + """ + shelf = {} # склад + in_work = {} # выдано + log = [] # журнал + __current_num = 1000 + + def __init__(self, shelf=None): + if shelf is None: + shelf = {} + self.take_storage_equipments(shelf) + + def take_storage_equipments(self, equipments): + """Принять на хранение списком + :param equipments: + :return: + """ + for machine in equipments: + self.take_storage(machine) + + def take_storage(self, equipment): + """Принять на хранение + :param equipment: + :return: + """ + if isinstance(equipment, OfficeEquipment): + for _ in range(equipment.number): + self.__current_num += 1 + equipment.inventory_number = self.__current_num + self.shelf[self.__current_num] = equipment + self.log_operation('Прием', equipment) + + def find_by_inventory(self, number): + """Найти по Инв + :param number: + :return: + """ + return self.shelf[number] + + def move_in_work(self, inventory, division): + """Выдать в подразделение + :param inventory: + :param division: + :return: + """ + equipment = self.shelf[inventory] + self.in_work[inventory] = (equipment, division) + del (self.shelf[inventory]) + self.log_operation('Выдано', equipment, division=division) + + def move_in_shelf(self, inventory): + """Вернуть на склад + :param inventory: + :return: + """ + equipment, _ = self.in_work[inventory] + self.shelf[inventory] = equipment + del (self.in_work[inventory]) + self.log_operation('Возврат', equipment) + + def print_shelf(self): + for inventory, equipment in self.shelf.items(): + print(equipment) + + def print_in_work(self): + for inventory, (equipment, division) in self.in_work.items(): + print(f'{equipment} {division}') + + def log_operation(self, operation, equipment, division=''): + """Логирование операции + :param operation: + :param equipment: + :param division: + :return: + """ + self.log.append(f' {datetime.datetime.now().isoformat()} - {operation} : {equipment} {division}') + + def log_print(self): + for line in self.log: + print(line) + + +class OfficeEquipment: + brand = '' + model = '' + inventory_number = 0 + dimensions = (0, 0) + weight = 0 + place = (0, 0) + is_network = False + number = 0 + type = '' + + def __init__(self, brand, model, number=1): + self.brand = brand + self.model = model + self.number = number + + def __str__(self): + return f'{self.inventory_number} {self.type} {self.brand} {self.model}' + + +class Printer(OfficeEquipment): + type = 'Принтер' + letter_size = '' + color = False + + +class CopyMachine(OfficeEquipment): + type = 'Копир' + auto_feeder = False + + +class Scanner(OfficeEquipment): + type = 'Сканер' + is_pdf_ready = False + + +class MenuController: + __WH = None + + def __init__(self, wh: WarehouseEquipments): + self.__WH = wh + self.builder = [None, Printer, Scanner, CopyMachine] # Создать Об по типу + # меню операций + self.action = [lambda: True, + self.refresh, self.add_equipment, self.move_in_work, self.move_shelf, self.log_print] + + def run(self): + """ Главный цикл приложения + :return: + """ + while True: + self.action[1]() # обновить экран + if self.action[self.print_menu()](): + break + + def log_print(self): + print('=== Журнал операций') + self.__WH.log_print() + + def print_menu(self): + print('1 - Обновить | 2 - Добавить | 3 - Выдать | 4 - Принять') + print('-----------') + print('5 - Журнал операций') + print('0 - Выход') + return self.input_int('? :') + + def refresh(self): + print('=== Cocтояние склада') + self.__WH.print_shelf() + print(f'=== Итого: {len(self.__WH.shelf)}') + print('') + print('=== Выдано') + self.__WH.print_in_work() + print(f'=== Итого: {len(self.__WH.in_work)}') + print('') + return False + + def add_equipment(self): + print('=== Введите оборудование') + type_eq = input('Модель (1-Принтер, 2-Сканер, 3-Копир) :') + brand = input('Бренд :') + model = input('Модель:') + number = self.input_int('Количество :') + eq = self.builder[int(type_eq)](brand, model, int(number)) + self.__WH.take_storage(eq) + return False + + def move_in_work(self): + inventory = self.input_int('ВВедите инв N :') + division = input('Введите отдел :') + self.__WH.move_in_work(int(inventory), division) + return False + + def move_shelf(self): + inventory = input('ВВедите инв N :') + self.__WH.move_in_shelf(int(inventory)) + return False + + @staticmethod + def input_int(text): + while True: + buf = input(text) + if buf.isdigit(): + return int(buf) + + +class SideKick: + """ + Наполнение склада + """ + + @staticmethod + def full_wh(wh: WarehouseEquipments): + sc_1 = Scanner('Canon', 'CanoScan LiDE 400') + sc_2 = Scanner('Epson', 'Perfection V19') + sc_3 = Scanner('Panasonic', 'KV-SL1066') + pr_1 = Printer('Xerox', 'Phaser 3020BI') + pr_2 = Printer('HP', 'LaserJet Pro M15w') + pr_3 = Printer('Brother', 'HL-L2340DWR') + cp_1 = CopyMachine('Xerox', 'B1022') + cp_2 = CopyMachine('Xerox', 'B215') + cp_3 = CopyMachine('Konica-Minolta', 'A0XY026') + wh.take_storage_equipments([sc_1, sc_2, sc_3, pr_1, pr_2, pr_3, cp_1, cp_3, cp_2]) + wh.move_in_work(1005, 'Secretary') + wh.move_in_work(1006, 'Secretary') + wh.move_in_work(1007, 'R&D') + wh.move_in_shelf(1005) + wh.move_in_shelf(1006) + + +if __name__ == '__main__': + wh1 = WarehouseEquipments() + SideKick.full_wh(wh1) + MenuController(wh1).run() diff --git a/homeworks/les08/task07.py b/homeworks/les08/task07.py new file mode 100644 index 0000000..fa2f4b6 --- /dev/null +++ b/homeworks/les08/task07.py @@ -0,0 +1,51 @@ +"""7. Реализовать проект «Операции с комплексными числами». Создайте класс «Комплексное число», реализуйте перегрузку +методов сложения и умножения комплексных чисел. Проверьте работу проекта, создав экземпляры класса (комплексные +числа) и выполнив сложение и умножение созданных экземпляров. Проверьте корректность полученного результата. """ + + +class Complex: + def __init__(self, re=0, im=0): + self.Re = re + self.Im = im + self.I1 = 'j' # в Python + + def __str__(self): + # реализовано идентично complex + if self.Re != 0: + buf = f'({self.Re}{self.Im:+}{self.I1})' + else: + buf = f'{self.Im:-}{self.I1}' + return buf + + def __add__(self, other): + return Complex(self.Re + other.Re, self.Im + other.Im) + + def __sub__(self, other): + return Complex(self.Re - other.Re, self.Im - other.Im) + + def __mul__(self, other): + # (a + bi) · (c + di) = (ac – bd) + (ad + bc)i + re = self.Re * other.Re - self.Im * other.Im + im = self.Re * other.Im + self.Im * other.Re + return Complex(re, im) + + +if __name__ == '__main__': + a = Complex(1, 3) + a1 = complex(1, 3) + print(a, a1) + assert str(a) == str(a1), 'Не равно представление' + print(Complex(0), Complex(0, 1), Complex(0, -1)) + assert str(Complex(0)) == str(complex(0)), 'Не равно представление' + assert str(Complex(0, 1)) == str(complex(0, 1)), 'Не равно представление' + assert str(Complex(0, -1)) == str(complex(0, -1)), 'Не равно представление' + b = Complex(4, -5) + b1 = complex(4, -5) + assert str(b) == str(b1), 'Не равно представление отрицательных чисел' + print(a, b, a1, b1) + print(a + b, a1 + b1) + assert str(a + b) == str(a1 + b1), 'Не равен результат сложения' + print(a - b, a1 - b1) + assert str(a - b) == str(a1 - b1), 'Не равен результат вычитания' + print(a * b, a1 * b1) + assert str(a * b) == str(a1 * b1), 'Не равен результат умножения'