From acf6c1a593994f83a0ab05e52e367dfd0c238f92 Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Fri, 22 Apr 2022 08:26:51 +0300 Subject: [PATCH 01/10] hometask 2 tasks complete --- lesson_2/hometask/task_1.py | 23 ++++++++++++ lesson_2/hometask/task_2.py | 20 +++++++++++ lesson_2/hometask/task_3.py | 30 ++++++++++++++++ lesson_2/hometask/task_4.py | 9 +++++ lesson_2/hometask/task_5.py | 35 +++++++++++++++++++ lesson_2/hometask/task_6.py | 70 +++++++++++++++++++++++++++++++++++++ 6 files changed, 187 insertions(+) create mode 100644 lesson_2/hometask/task_1.py create mode 100644 lesson_2/hometask/task_2.py create mode 100644 lesson_2/hometask/task_3.py create mode 100644 lesson_2/hometask/task_4.py create mode 100644 lesson_2/hometask/task_5.py create mode 100644 lesson_2/hometask/task_6.py diff --git a/lesson_2/hometask/task_1.py b/lesson_2/hometask/task_1.py new file mode 100644 index 0000000..18df34f --- /dev/null +++ b/lesson_2/hometask/task_1.py @@ -0,0 +1,23 @@ +import datetime + +# Создать список и заполнить его элементами различных типов данных. +# Реализовать скрипт проверки типа данных каждого элемента. +# !!!(Что значит "проверки типов данных"? У нас разве есть ограничения??) +# Использовать функцию type() для проверки типа. +# Элементы списка можно не запрашивать у пользователя, а указать явно, в программе. + +# задам априори, так как типов данных куча, писать ifы лень)) +mylist = ["iron maiden", 666, "the number of the beast", 4.85, datetime.date(1982, 3, 22)] + +for element in mylist: + print(f"{element} has a type {type(element)}") + +# !!!(Что значит "проверки типов данных"? У нас разве есть ограничения??) +# пусть есть +# множество с допустимыми значениями +allow_types_set = frozenset((type(int()), type(str()), type(float()))) +for element in mylist: + element_type = type(element) + if element_type not in allow_types_set: + mylist.remove(element) + print(f"element {element} has a not allowed type {element_type}") \ No newline at end of file diff --git a/lesson_2/hometask/task_2.py b/lesson_2/hometask/task_2.py new file mode 100644 index 0000000..2fb9246 --- /dev/null +++ b/lesson_2/hometask/task_2.py @@ -0,0 +1,20 @@ +import datetime + +# Для списка реализовать обмен значений соседних элементов, +# т.е. Значениями обмениваются элементы с индексами 0 и 1, 2 и 3 и т.д. +# При нечетном количестве элементов последний сохранить на своем месте. +# Для заполнения списка элементов необходимо использовать функцию input() + +my_list = [] +while True: + x = input("Enter list value. If no value entered, list ends >>>") + if x == "": + break + my_list.append(x) + +print(f"entered list is {my_list}") +# нас интересующие индексы чётных элементов +for indx in range(0, (len(my_list)//2)*2, 2): + my_list[indx], my_list[indx + 1] = my_list[indx + 1], my_list[indx] + +print(f"result list is {my_list}") diff --git a/lesson_2/hometask/task_3.py b/lesson_2/hometask/task_3.py new file mode 100644 index 0000000..10ea97c --- /dev/null +++ b/lesson_2/hometask/task_3.py @@ -0,0 +1,30 @@ +# Пользователь вводит месяц в виде целого числа от 1 до 12. +# Сообщить к какому времени года относится месяц (зима, весна, лето, осень). +# Напишите решениЯ через list и через dict. + +number = None + +while True: + try: + number = int(input("Enter number in range from 1 to 12 >>>")) + if number in range(1, 12): + break + except ValueError: + continue +# решение через dict +# кортежи - хэшируемый тип данных +seasons_dict = {(12, 1, 2): "winter", (3, 4, 5): "spring", (6, 7, 8): "summer", (9, 10, 11): "autumn/fall"} +for month_numbers, name in seasons_dict.items(): + if number in month_numbers: + print(f"month with number {number} is {name}") + # больше исследовать нечего + break + +# решение через list +seasons_name_list = ["winter", "spring", "summer", "autumn/fall"] +seasons_month_list = [(12, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)] +for month_numbers, name in zip(seasons_month_list, seasons_name_list): + if number in month_numbers: + print(f"month with number {number} is {name}") + # больше исследовать нечего + break diff --git a/lesson_2/hometask/task_4.py b/lesson_2/hometask/task_4.py new file mode 100644 index 0000000..4913797 --- /dev/null +++ b/lesson_2/hometask/task_4.py @@ -0,0 +1,9 @@ +# Пользователь вводит строку из нескольких слов, разделённых пробелами. +# Вывести каждое слово с новой строки. +# Строки необходимо пронумеровать. +# Если в слово длинное, выводить только первые 10 букв в слове. + +# Пользователь может ввести что угодно +word_list = input("Enter an ordinary string >>>").split() +for number, word in enumerate(word_list, 1): + print(f"{number} {word:.10}") diff --git a/lesson_2/hometask/task_5.py b/lesson_2/hometask/task_5.py new file mode 100644 index 0000000..79ae720 --- /dev/null +++ b/lesson_2/hometask/task_5.py @@ -0,0 +1,35 @@ +# Реализовать структуру «Рейтинг», представляющую собой +# не возрастающий набор натуральных чисел. +# У пользователя необходимо запрашивать новый элемент рейтинга. +# Если в рейтинге существуют элементы с одинаковыми значениями, +# то новый элемент с тем же значением должен разместиться после них. +# +# **Подсказка.** Например, набор натуральных чисел: 7, 5, 3, 3, 2. +# Пользователь ввел число 3. Результат: 7, 5, 3, 3, 3, 2. +# Пользователь ввел число 8. Результат: 8, 7, 5, 3, 3, 2. +# Пользователь ввел число 1. Результат: 7, 5, 3, 3, 2, 1. +# +# Набор натуральных чисел можно задать непосредственно в коде, например, my_list = [7, 5, 3, 3, 2]. + +# "...новый элемент...должен разместиться после них..." - значит, +# просто добавить элемент и сортировать список - не то, что требуется. + +my_list = [7, 5, 3, 3, 2] +number = None + +while True: + try: + number = int(input("Enter natural number >>>")) + if number >= 0: + break + except ValueError: + continue + +if number > my_list[0]: + my_list.insert(0, number) +else: + for indx in range(len(my_list) - 1, -1, -1): + if number <= my_list[indx]: + my_list.insert(indx + 1, number) + break +print(my_list) diff --git a/lesson_2/hometask/task_6.py b/lesson_2/hometask/task_6.py new file mode 100644 index 0000000..f3dd2aa --- /dev/null +++ b/lesson_2/hometask/task_6.py @@ -0,0 +1,70 @@ +# *Реализовать структуру данных «Товары». +# Она должна представлять собой список кортежей. +# Каждый кортеж хранит информацию об отдельном товаре. +# В кортеже должно быть два элемента — номер товара и словарь с параметрами +# (характеристиками товара: название, цена, количество, единица измерения). +# Структуру нужно сформировать программно, т.е. запрашивать все данные у пользователя. +# **Пример готовой структуры:** +# [ +# (1, {“название”: “компьютер”, “цена”: 20000, “количество”: 5, “eд”: “шт.”}), +# (2, {“название”: “принтер”, “цена”: 6000, “количество”: 2, “eд”: “шт.”}), +# (3, {“название”: “сканер”, “цена”: 2000, “количество”: 7, “eд”: “шт.”}) +# ] +# Необходимо собрать аналитику о товарах. +# Реализовать словарь, в котором каждый ключ — характеристика товара, +# например название, а значение — список значений-характеристик, например список названий товаров. +# **Пример:** +# { +# “название”: [“компьютер”, “принтер”, “сканер”], +# “цена”: [20000, 6000, 2000], +# “количество”: [5, 2, 7], +# “ед”: [“шт.”] +# } + +product_list = list() +# Запрашиваем данные у пользователя +while True: + try: + number = int(input("Enter the product number >>>")) + double_mark = False + # стоило бы добавить проверку дубляжей... + for item in product_list: + if item[0] == number: + double_mark = True + break + if double_mark: + print(f"Number {number} already in list") + continue + name = input("Enter the product name >>>") + price = float(input("Enter the product price >>>")) + count = int(input("Enter the product count >>>")) + value_measure = input("Enter the product measure >>>") + except ValueError as verror: + print(f"{verror}, uncorrect value") + continue + except EOFError as eof_error: + print(f"{eof_error}, now quit") + quit() + if name == "" or value_measure == "" or price < 0 or count < 0 or number < 0: + print(f"uncorrect values detected, reenter please") + continue + product_list.append((number, {'name': name, 'price': price, 'count': count, 'measure': value_measure})) + if input("Press Enter to continue or something else to break >>>") == "": + break +print(product_list) + +# Теперь парсим словарь в другой словарь +unique_dict = dict() +for values in product_list: + if len(values) < 2: + continue + product_dict = values[1] + if type(product_dict) is not dict: + continue + for key, value in product_dict.items(): + unique_list = unique_dict.setdefault(key, list()) + # судя по примеру, в массиве должны быть только уникальные значения + if value not in unique_list: + unique_list.append(value) + +print(unique_dict) From 986610525b547c4f075152dfe351b88043e8792f Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Sat, 23 Apr 2022 11:23:57 +0300 Subject: [PATCH 02/10] Empty list case fix --- lesson_2/hometask/task_5.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lesson_2/hometask/task_5.py b/lesson_2/hometask/task_5.py index 79ae720..ad3c56d 100644 --- a/lesson_2/hometask/task_5.py +++ b/lesson_2/hometask/task_5.py @@ -24,8 +24,9 @@ break except ValueError: continue - -if number > my_list[0]: +if len(my_list) == 0: + my_list.append(number) +elif number > my_list[0]: my_list.insert(0, number) else: for indx in range(len(my_list) - 1, -1, -1): From a32f0200edb3b3ad4a14cdf8a3eabbf3ac451f07 Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Wed, 27 Apr 2022 22:03:24 +0300 Subject: [PATCH 03/10] Hometask 3 complete --- lesson_3/hometask/hometask_1.py | 33 ++++++++ lesson_3/hometask/hometask_2.py | 36 +++++++++ lesson_3/hometask/hometask_3.py | 48 ++++++++++++ lesson_3/hometask/hometask_4.py | 133 ++++++++++++++++++++++++++++++++ lesson_3/hometask/hometask_5.py | 41 ++++++++++ lesson_3/hometask/hometask_6.py | 23 ++++++ 6 files changed, 314 insertions(+) create mode 100644 lesson_3/hometask/hometask_1.py create mode 100644 lesson_3/hometask/hometask_2.py create mode 100644 lesson_3/hometask/hometask_3.py create mode 100644 lesson_3/hometask/hometask_4.py create mode 100644 lesson_3/hometask/hometask_5.py create mode 100644 lesson_3/hometask/hometask_6.py diff --git a/lesson_3/hometask/hometask_1.py b/lesson_3/hometask/hometask_1.py new file mode 100644 index 0000000..e8a436a --- /dev/null +++ b/lesson_3/hometask/hometask_1.py @@ -0,0 +1,33 @@ +# Реализовать функцию, принимающую два числа (позиционные аргументы) +# и выполняющую их деление. Числа запрашивать у пользователя, +# предусмотреть обработку ситуации деления на ноль. + +# нас интересуют только позиционные аргументы +# ни о каких именованных и позиционных аргументах речь не идёт! +def divide_numbers(num_1, num_2, /): + """ + Функция вычисления частного от деления одного числа на другое + + :param num_1: делимое + :param num_2: делитель + :return: результат деления делимого на делитель или None + """ + try: + return num_1 / num_2 + except ZeroDivisionError: + return None + + +divident = float() +denominator = float() +while True: + try: + divident = float(input("Введите числитель дроби:")) + denominator = float(input("Введите знаменатель дроби:")) + break + except ValueError: + continue + +print(f"{divident}/{denominator}={divide_numbers(divident, denominator)}") +# Тут будет ошибка! Так как аргументы строго позиционные +# print(f"{divident}/{denominator}={divide_numbers(num1 = divident, num2 = denominator)}") diff --git a/lesson_3/hometask/hometask_2.py b/lesson_3/hometask/hometask_2.py new file mode 100644 index 0000000..ca09521 --- /dev/null +++ b/lesson_3/hometask/hometask_2.py @@ -0,0 +1,36 @@ +# Реализовать функцию, принимающую несколько параметров, описывающих данные пользователя: +# имя, фамилия, год рождения, город проживания, email, телефон. +# Функция должна принимать параметры как именованные аргументы. +# Реализовать вывод данных о пользователе одной строкой. + +import datetime + + +# Только именованные аргументы! +# значения по умолчанию не придумал) +def get_user_data(*, name, surname, birthdate, location, email=None, phone=None): + """ + Возвращает информацию о пользователе на основе задаваемых данных. + + :param name: имя пользователя + :param surname: фамилия пользователя + :param birthdate: дата рождения пользователя + :param location: местоположение пользователя + :param email: электронная почта пользователя + :param phone: телефон пользователя + :return: информация о пользователе в одной строке + """ + return f"Oh that obnoxious user {name} {surname}! " \ + f"He was born in {birthdate}. " \ + f"Now {name} located on {location}. " \ + f"You may reach {name} by phone {phone} or email {email}" + + +print(get_user_data(name="Louis", birthdate=datetime.date(year=1973, month=2, day=11), + surname="Cachet", location="Demont", + phone="+33-61-666-14-88", email="christian@jw.fr")) + +# ошибка! +# print(get_user_data("Louis", birthdate=datetime.date(year=1973, month=2, day=11), +# surname="Cachet", location="Demont", +# phone="+33-61-666-14-88", email="christian@jw.fr")) diff --git a/lesson_3/hometask/hometask_3.py b/lesson_3/hometask/hometask_3.py new file mode 100644 index 0000000..3ee1651 --- /dev/null +++ b/lesson_3/hometask/hometask_3.py @@ -0,0 +1,48 @@ +# Реализовать функцию my_func(), которая +# принимает три позиционных аргумента, и +# возвращает сумму наибольших двух аргументов. +import math + + +# вспомогательная функция +def calc_sum(*args): + """ + Вычисляет сумму задаваемых чисел. + При некорректном типе аргументов возвращает минус бесконечность + + :param args: задаваемые числа + :return: сумму задаваемых чисел или -math.inf + """ + try: + return sum(args) + except TypeError: + return -math.inf + + +# нас интересуют только позиционные аргументы, +# ни о каких именованных и позиционных аргументах речь не идёт! +def my_func(arg_1, arg_2, arg_3, /): + """ + Вычисляет сумму наибольших двух аргументов. + При некорректном типе двух задаваемых аргументов возвращает минус бесконечность + + :param arg_1: некое целое или дробное число + :param arg_2: некое целое или дробное число + :param arg_3: некое целое или дробное число + :return: сумму наибольших двух аргументов или -math.inf + """ + return max(calc_sum(arg_1, arg_2), + calc_sum(arg_1, arg_3), + calc_sum(arg_2, arg_3)) + + +def lazy_print(arg_1, arg_2, arg_3): + print(f"Max sum of two elements " + f" between {arg_1}, {arg_2}, {arg_3} is " + f"{my_func(arg_1, arg_2, arg_3)}") + + +lazy_print('ahh', 2, 3) +lazy_print(3, 1, 4) +lazy_print(3.13, 5, 9.11) +lazy_print('ahh', 'fggh', 3) diff --git a/lesson_3/hometask/hometask_4.py b/lesson_3/hometask/hometask_4.py new file mode 100644 index 0000000..5c40be7 --- /dev/null +++ b/lesson_3/hometask/hometask_4.py @@ -0,0 +1,133 @@ +# Программа принимает действительное положительное число x и целое отрицательное число y. +# Необходимо выполнить возведение числа x в степень y. +# Задание необходимо реализовать в виде функции my_func(x, y). +# При решении задания необходимо обойтись без встроенной функции возведения числа в степень. +# ** Подсказка:** попробуйте решить задачу двумя способами. +# Первый — возведение в степень с помощью оператора **. +# Второй — более сложная реализация без оператора **, предусматривающая использование цикла. +import math + + +def my_func_var_1(base, exp): + """ + Алгоритм возведения числа в степень. + + :param base: Число, которое требуется возвести в степень + :param exp: степень, в которую требуется возвести число + :return: число, возведенное в степень + """ + return base ** exp + + +# a^x == exp(x*ln(a)) +# универсальна, расчёт дробных корней прост +# если нет претензий к math.log и math.exp +def my_func_var_2(base, exp): + """ + Алгоритм возведения числа в степень. + Базируеся на формуле a**x == exp(x*ln(a)) + + :param base: Положительное число, которое требуется возвести в степень + :param exp: степень, в которую требуется возвести число + :return: число, возведенное в степень + """ + if base < 0: + raise ValueError("base cannot be negative!") + return math.exp(exp * math.log(base)) + + +def my_func_var_3(base, exp): + """ + Иттерационный алгоритм возведения числа в целую степень. + + :param base: Число, которое требуется возвести в степень + :param exp: степень, в которую требуется возвести число + :return: число, возведенное в степень + """ + if type(exp) != int: + raise TypeError("Uncorrect exponent type") + sign = -1 if (exp < 0) else 1 + res = 1 + for step in range(exp * sign): + res *= base + return res if sign == 1 else 1 / res + + +def my_func_var_4(base, exp): + """ + Быстрый алгоритм возведения числа в целую степень. + Базируется на предствалении числа в бинарном виде + и формулах: + -> a**(x*y) = (a**x)**y; + -> a**(x+y) = (a**x)*(a**y). + Выполнен в соответствие с: + https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%B1%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B3%D0%BE_%D0%B2%D0%BE%D0%B7%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D1%8C + + :param base: Число, которое требуется возвести в степень + :param exp: целая степень, в которую требуется возвести число + :return: число, возведенное в степень + """ + if type(exp) != int: + raise TypeError("Uncorrect exponent type") + sign = -1 if (exp < 0) else 1 + bin_repr = bin(exp * sign) + res = 1 + for bit in bin_repr[2:len(bin_repr)]: + res *= res * base if bit == '1' else res + return res if sign == 1 else 1 / res + + +# BONUS: +def my_math_root(base, exp, max_error=1e-10): + """ + Алгоритм оценки корня целой степени из числа. + Выполнен в соответствие с: + https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BD%D0%B0%D1%85%D0%BE%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BA%D0%BE%D1%80%D0%BD%D1%8F_n-%D0%BD%D0%BE%D0%B9_%D1%81%D1%82%D0%B5%D0%BF%D0%B5%D0%BD%D0%B8 + + :param base: Число, из которого требуется извлечь корень + :param exp: целая степень корня + :param max_error: требуемая точность оценки корня + :return: оценка корня заданной степени из числа или + None, если корень с требуемой точностью оценить не удалось + """ + if type(exp) != int: + raise TypeError("Uncorrect exponent type") + if exp % 2 == 0 and base < 0: + raise ValueError("Cannot estimate negative base root by even exp") + if exp == 0: + return 1 + new_exp = exp if exp > 0 else -exp + xk = x0 = base + # ограничитель цикла + max_cycle_number = 3000 + for i in range(max_cycle_number): + xk = (1 / new_exp) * ((new_exp - 1) * xk + base / my_func_var_4(xk, new_exp - 1)) + if math.fabs(xk - x0) < max_error: + # сходимость достигнута + return xk if exp > 0 else 1 / xk + x0 = xk + # Если количество итераций превыщено, результат не гарантирован! + return None + + +def test_my_funcs(x, y): + var_1 = my_func_var_1(x, y) +# var_2 = my_func_var_2(x, y) + var_3 = my_func_var_3(x, y) + var_4 = my_func_var_4(x, y) + root = my_math_root(x, y) + nominal = pow(x, y) + root_nominal = pow(x, 1 / y) + print(f"Results of power {x} to {y}:\n" + f"variant 1 is {var_1}, error to pow is {math.fabs(var_1 - nominal)}\n" +# f"variant 2 is {var_2}, error to pow is {math.fabs(var_2 - nominal)}\n" + f"variant 3 is {var_3}, error to pow is {math.fabs(var_3 - nominal)}\n" + f"variant 4 is {var_4}, error to pow is {math.fabs(var_4 - nominal)}") + print(f"Special test: my_math_root {x} by {y} of power {x} to {1 / y} (same as root {x} by {y}):") + print(f"my_math_root is {root}") + print(f"error to pow is {math.fabs(root - root_nominal)}") + + +test_my_funcs(50.4564654546, -31) + +print(my_math_root(5.11568, -2, 1e-30) - pow(5.11568, -1 / 2)) diff --git a/lesson_3/hometask/hometask_5.py b/lesson_3/hometask/hometask_5.py new file mode 100644 index 0000000..abb47c0 --- /dev/null +++ b/lesson_3/hometask/hometask_5.py @@ -0,0 +1,41 @@ +# Программа запрашивает у пользователя строку чисел, разделенных пробелом. +# При нажатии Enter должна выводиться сумма чисел. +# Пользователь может продолжить ввод чисел, разделенных пробелом и снова нажать Enter. +# Сумма вновь введенных чисел будет добавляться к уже подсчитанной сумме. +# Но если вместо числа вводится специальный символ, выполнение программы завершается. +# Если специальный символ введен после нескольких чисел, то +# вначале нужно добавить сумму этих чисел к полученной ранее сумме и после этого завершить программу. + +def get_number_by_string(string_number): + """ + Функция преобразования строки к какому-либо числовому формату + + :param string_number: число в строковом виде + :return: число в числовом формате + """ + try: + return int(string_number) + except ValueError: + # если и тут ошибка, пробрасываем + # во внешний код + return float(string_number) + +# если введен нечисловой символ (но и не специальный) после нескольких чисел, то +# - вначале нужно добавить сумму этих чисел к полученной ранее сумме; +# - пользователь может продолжить ввод чисел, разделенных пробелом и снова нажать Enter. +final_sum = 0 +while True: + input_string = input("Enter the numbers string with ' ' as delimiter; in '$' in string, nothing to be more >>>") + input_array = input_string.split() + try: + # Подсчёт суммы ведётся до первого нечислового символа ('4d' - тоже не числовой символ) + for element in input_array: + # возможно, пользователя будет интересовать + # именно сумма целых чисел, а плавающая запятая - раздражать + final_sum += get_number_by_string(element) + except ValueError: + # считаем, что, например, '3.12$' - уже не число + if '$' in input_string: + break + finally: + print("Current sum is ", final_sum) \ No newline at end of file diff --git a/lesson_3/hometask/hometask_6.py b/lesson_3/hometask/hometask_6.py new file mode 100644 index 0000000..c6028cf --- /dev/null +++ b/lesson_3/hometask/hometask_6.py @@ -0,0 +1,23 @@ +# Реализовать функцию int_func(), принимающую слово из маленьких латинских букв и возвращающую его же, +# но с прописной первой буквой. +# Например, print(int_func(‘text’)) -> Text. +# Продолжить работу над заданием. +# В программу должна попадать строка из слов, разделенных пробелом. +# Каждое слово состоит из латинских букв в нижнем регистре. +# Сделать вывод исходной строки, но каждое слово должно начинаться с заглавной буквы. +# Необходимо использовать написанную ранее функцию int_func(). + +def int_func(string): + return string.capitalize() + + +# строки разделены пробелом +string_array = input("Input a string >>>").split(" ") + +for element_index in range(len(string_array)): + string_element = string_array[element_index] + if " " in string_element or string_element.isdigit(): + continue + string_array[element_index] = int_func(string_element) + +print(' '.join(string_array)) From 61d150ca10b8329b7e0bfac3e8d192e94ca89a07 Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Sun, 1 May 2022 19:35:56 +0300 Subject: [PATCH 04/10] 4th hometask complete --- lesson_4/hometask/task_1.py | 31 +++++++++++++++++++ lesson_4/hometask/task_2.py | 32 ++++++++++++++++++++ lesson_4/hometask/task_3.py | 6 ++++ lesson_4/hometask/task_4.py | 20 +++++++++++++ lesson_4/hometask/task_5.py | 13 ++++++++ lesson_4/hometask/task_6_part_a.py | 48 ++++++++++++++++++++++++++++++ lesson_4/hometask/task_6_part_b.py | 37 +++++++++++++++++++++++ lesson_4/hometask/task_7.py | 37 +++++++++++++++++++++++ 8 files changed, 224 insertions(+) create mode 100644 lesson_4/hometask/task_1.py create mode 100644 lesson_4/hometask/task_2.py create mode 100644 lesson_4/hometask/task_3.py create mode 100644 lesson_4/hometask/task_4.py create mode 100644 lesson_4/hometask/task_5.py create mode 100644 lesson_4/hometask/task_6_part_a.py create mode 100644 lesson_4/hometask/task_6_part_b.py create mode 100644 lesson_4/hometask/task_7.py diff --git a/lesson_4/hometask/task_1.py b/lesson_4/hometask/task_1.py new file mode 100644 index 0000000..932d36e --- /dev/null +++ b/lesson_4/hometask/task_1.py @@ -0,0 +1,31 @@ +# Реализовать скрипт, в котором должна быть предусмотрена +# функция расчета заработной платы сотрудника. +# В расчете необходимо использовать формулу: +# (выработка в часах*ставка в час) + премия. +# Для выполнения расчета для конкретных значений необходимо запускать скрипт с параметрами. +from sys import argv + + +# calculate_salary = lambda work_hours, rate_per_hour, bonus: work_hours * rate_per_hour + bonus +def calculate_salary(work_hours: float, rate_per_hour: float, bonus: float): + """ + Расчёт ЗП сотрудника + + :param work_hours: отработанные за месяц часы, [ч] + :param rate_per_hour: ставка сотрудника за час, [денег/ч] + :param bonus: премия, [деньги] + :return: ЗП сотрудника за месяц, [деньги] + """ + return work_hours * rate_per_hour + bonus + + +try: + filepath, work_hours, rate_per_hour, bonus, *others = argv + work_hours = float(work_hours) + rate_per_hour = float(rate_per_hour) + bonus = float(bonus) +except ValueError: + print("Sorry, it's need a 3 float parameters for calculations!") + exit() + +print(f"Сотрудник заработал {calculate_salary(work_hours, rate_per_hour, bonus)} за месяц") diff --git a/lesson_4/hometask/task_2.py b/lesson_4/hometask/task_2.py new file mode 100644 index 0000000..a0a1f24 --- /dev/null +++ b/lesson_4/hometask/task_2.py @@ -0,0 +1,32 @@ +# Представлен список чисел. +# Необходимо вывести элементы исходного списка, значения которых больше предыдущего элемента. +# +# **Подсказка:** элементы, удовлетворяющие условию, оформить в виде списка. +# Для формирования списка использовать генератор. +# **Пример исходного списка:** [300, 2, 12, 44, 1, 1, 4, 10, 7, 1, 78, 123, 55]. +# **Результат:** [12, 44, 4, 10, 78, 123]. +# origin_list = [300, 2, 12, 44, 44.5, 1, 1, 4, 10, 7, 1, 78, 123, 55] + +def get_number_by_string(string_number: str): + """ + Функция преобразования строки к какому-либо числовому формату + + :param string_number: число в строковом виде + :return: число в числовом формате + """ + try: + return int(string_number) + except ValueError: + # если и тут ошибка, пробрасываем во внешний код + return float(string_number) + + +# не хочу, чтобы это запускалось в других модулях +# https://docs.python.org/3/library/__main__.html +if __name__ == "__main__": + input_string_array = input("Enter the numbers string with ' ' as delimiter>>>").split() + origin_list = [get_number_by_string(num) for num in input_string_array] + # Выглядит красивее + # print([element for i, element in enumerate(origin_list) if element > origin_list[i - 1 if i > 0 else 0]]) + # Зато тут на один шаг меньше + print([origin_list[i] for i in range(1, len(origin_list)) if origin_list[i] > origin_list[i - 1]]) diff --git a/lesson_4/hometask/task_3.py b/lesson_4/hometask/task_3.py new file mode 100644 index 0000000..f46d1ed --- /dev/null +++ b/lesson_4/hometask/task_3.py @@ -0,0 +1,6 @@ +# Для чисел в пределах от 20 до 240 найти числа, кратные 20 или 21. +# Необходимо решить задание в одну строку. +# **Подсказка:** использовать функцию range() и генератор. + +# Полагаю, что 240 включено в интервал +print([x for x in range(20, 241) if x % 20 == 0 or x % 21 == 0]) diff --git a/lesson_4/hometask/task_4.py b/lesson_4/hometask/task_4.py new file mode 100644 index 0000000..174abf8 --- /dev/null +++ b/lesson_4/hometask/task_4.py @@ -0,0 +1,20 @@ +# Представлен список чисел. +# Определить элементы списка, не имеющие повторений. +# Сформировать итоговый массив чисел, соответствующих требованию. +# Элементы вывести в порядке их следования в исходном списке. +# Для выполнения задания обязательно использовать генератор. +# +# **Пример исходного списка:** +# [2, 2, 2, 7, 23, 1, 44, 44, 3, 2, 10, 7, 4, 11]. +# **Результат:** +# [23, 1, 3, 10, 4, 11] + +import task_2 + +input_string_array = input("Enter the numbers string with ' ' as delimiter>>>").split() +origin_list = [task_2.get_number_by_string(num) for num in input_string_array] +print(origin_list) + +# origin_list = [2, 2, 2, 7, 23, 1, 44, 44, 3, 2, 10, 7, 4, 11] + +print([x for x in origin_list if origin_list.count(x) == 1]) diff --git a/lesson_4/hometask/task_5.py b/lesson_4/hometask/task_5.py new file mode 100644 index 0000000..30abe6c --- /dev/null +++ b/lesson_4/hometask/task_5.py @@ -0,0 +1,13 @@ +# Реализовать формирование списка, используя функцию range() и возможности генератора. +# В список должны войти четные числа от 100 до 1000 (включая границы). +# Необходимо получить результат вычисления произведения всех элементов списка. +# +# **Подсказка:** использовать функцию reduce(). +import functools as f_tools + +# even_numbers = [num for num in range(100, 1001) if num % 2 == 0] +# так быстрее +even_numbers = [num for num in range(100, 1001, 2)] + +print(f"Multiplication of all even number" + f"in range 100 to 1000 is {f_tools.reduce(lambda x, y: x * y, even_numbers)}") diff --git a/lesson_4/hometask/task_6_part_a.py b/lesson_4/hometask/task_6_part_a.py new file mode 100644 index 0000000..4429373 --- /dev/null +++ b/lesson_4/hometask/task_6_part_a.py @@ -0,0 +1,48 @@ +# Реализовать два небольших скрипта: +# а) итератор, генерирующий целые числа, начиная с указанного. +# +# !!!Note: так скрипт или всё-таки итератор? Итератор - это, разве, не объект?) ) +# +# **Подсказка:** использовать функцию count() и cycle() модуля itertools. +# Обратите внимание, что создаваемый цикл не должен быть бесконечным. +# Необходимо предусмотреть условие его завершения (Условие на пользователе или на создателе скрипта?). +# +# Например, в первом задании выводим целые числа, начиная с 3, +# а при достижении числа 10 завершаем цикл. + +# Как я понял эту часть задания: +# Пишем скрипт, использующий itertools.count +# Используем эту функцию в цикле в скрипте. +# Цикл прерывает пользователь. Или моё какое-то условие. +import itertools as itools + + +def my_count(start_number: int, step: int = 1): + """Одно из представлений itertools.count""" + current_number = start_number + while True: + yield current_number + current_number += step + + +# не хочу, чтобы это запускалось в других модулях +# https://docs.python.org/3/library/__main__.html +if __name__ == "__main__": + origin_number = 0 + # Запрашиваем + while True: + try: + origin_number = int(input("Enter origin integer number for generating a sequence >>>")) + max_cycle_number = int(input("Enter max cycle count >>>")) + except ValueError: + print("That's not integer number! Try again.") + continue + break + count = 0 + for num in itools.count(origin_number): +# for num in my_count(origin_number): + count += 1 + if count > max_cycle_number: + break + print(num) + print("That's all, folks!") diff --git a/lesson_4/hometask/task_6_part_b.py b/lesson_4/hometask/task_6_part_b.py new file mode 100644 index 0000000..cef6dfe --- /dev/null +++ b/lesson_4/hometask/task_6_part_b.py @@ -0,0 +1,37 @@ +# Реализовать два небольших скрипта: +# б) итератор, повторяющий элементы некоторого списка, определенного заранее. +# +# !!!Note: так скрипт или всё-таки итератор? Итератор - это, разве, не объект?) ) +# +# **Подсказка:** использовать функцию count() и cycle() модуля itertools. +# Обратите внимание, что создаваемый цикл не должен быть бесконечным. +# Необходимо предусмотреть условие его завершения.(Условие на пользователе или на создателе скрипта?). +# +# Например, во втором также необходимо предусмотреть условие, +# при котором повторение элементов списка будет прекращено. +import itertools as itools + +def my_cycle(iterate): + while iterate: + for element in iterate: + yield element + + +# https://docs.python.org/3/library/__main__.html +if __name__ == "__main__": + input_string_array = input("Enter the strings with ' ' as delimiter>>>").split() + while True: + try: + max_cycle_number = int(input("Enter max cycle count >>>")) + except ValueError: + print("That's not integer number! Try again.") + continue + break + count = 0 + for element in itools.cycle(input_string_array): +# for element in my_cycle(input_string_array): + count += 1 + if count > max_cycle_number: + break + print(element) + print("That's all, folks!") \ No newline at end of file diff --git a/lesson_4/hometask/task_7.py b/lesson_4/hometask/task_7.py new file mode 100644 index 0000000..a1ec248 --- /dev/null +++ b/lesson_4/hometask/task_7.py @@ -0,0 +1,37 @@ +# Реализовать генератор с помощью функции с ключевым словом yield, создающим очередное значение. +# При вызове функции должен создаваться объект-генератор. +# Функция должна вызываться следующим образом: for el in fact(n). +# Функция отвечает за получение факториала числа, а в цикле необходимо выводить только первые n чисел, +# начиная с 1! и до n!. +# +# **Подсказка:** факториал числа n — произведение чисел от 1 до n. +# Например, факториал четырёх 4! = 1 * 2 * 3 * 4 = 24. + +def fact(n: int): + if n < 0: + raise ValueError("Factorial not defined for a negative value!") + if n == 0: + yield 1 + current_value = 1 + for number in range(1, n + 1): + current_value *= number + yield current_value + + +origin_number = 0 +while True: + try: + origin_number = int(input("Enter non-negative integer number for generating a factorial sequence >>>")) + except ValueError: + print("That's not integer number! Try again.") + continue + break + +# creates generator object for checks +gen_obj = fact(origin_number) +print(f"fact({origin_number}) type is {type(gen_obj)}") +count = 0 +# for el in gen_obj: # то же самое, но не по заданию +for el in fact(origin_number): + count += 1 + print(f"{count}! : {el}") From 87a26d67a5770602bce612245bcdce16ebce307d Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Sat, 7 May 2022 10:09:29 +0300 Subject: [PATCH 05/10] Hometask 5 complete --- lesson_5/hometask/Firms.txt | 7 ++ lesson_5/hometask/Numbers.txt | 4 ++ lesson_5/hometask/company_dictlist.json | 1 + lesson_5/hometask/employeers_salaries.txt | 11 ++++ lesson_5/hometask/get_file_by_files_list.py | 51 +++++++++++++++ lesson_5/hometask/lessons.txt | 4 ++ lesson_5/hometask/new_numbers_file.txt | 4 ++ lesson_5/hometask/numeric_file.txt | 1 + lesson_5/hometask/task_1.py | 16 +++++ lesson_5/hometask/task_1_file.txt | 4 ++ lesson_5/hometask/task_2.py | 29 +++++++++ lesson_5/hometask/task_3.py | 27 ++++++++ lesson_5/hometask/task_4.py | 31 +++++++++ lesson_5/hometask/task_5.py | 33 ++++++++++ lesson_5/hometask/task_6.py | 29 +++++++++ lesson_5/hometask/task_7.py | 71 +++++++++++++++++++++ 16 files changed, 323 insertions(+) create mode 100644 lesson_5/hometask/Firms.txt create mode 100644 lesson_5/hometask/Numbers.txt create mode 100644 lesson_5/hometask/company_dictlist.json create mode 100644 lesson_5/hometask/employeers_salaries.txt create mode 100644 lesson_5/hometask/get_file_by_files_list.py create mode 100644 lesson_5/hometask/lessons.txt create mode 100644 lesson_5/hometask/new_numbers_file.txt create mode 100644 lesson_5/hometask/numeric_file.txt create mode 100644 lesson_5/hometask/task_1.py create mode 100644 lesson_5/hometask/task_1_file.txt create mode 100644 lesson_5/hometask/task_2.py create mode 100644 lesson_5/hometask/task_3.py create mode 100644 lesson_5/hometask/task_4.py create mode 100644 lesson_5/hometask/task_5.py create mode 100644 lesson_5/hometask/task_6.py create mode 100644 lesson_5/hometask/task_7.py diff --git a/lesson_5/hometask/Firms.txt b/lesson_5/hometask/Firms.txt new file mode 100644 index 0000000..8dbd38d --- /dev/null +++ b/lesson_5/hometask/Firms.txt @@ -0,0 +1,7 @@ +Horns & Hooves ЗАО -100 5000 +Pigbank ООО 0 100000 +Federates & Co ПАО 50 100500 +Employer ПАО 50000 1000 +Swineld Fancy Flight ООО 100000 3000 +Shavermier Inc ПАО 50000 1000 +Confederat & Co ОООО!!! 1000000.89 10000.79 \ No newline at end of file diff --git a/lesson_5/hometask/Numbers.txt b/lesson_5/hometask/Numbers.txt new file mode 100644 index 0000000..bebef41 --- /dev/null +++ b/lesson_5/hometask/Numbers.txt @@ -0,0 +1,4 @@ +One — 1 +Two — 2 +Four — 4 +Three — 3 diff --git a/lesson_5/hometask/company_dictlist.json b/lesson_5/hometask/company_dictlist.json new file mode 100644 index 0000000..dff9513 --- /dev/null +++ b/lesson_5/hometask/company_dictlist.json @@ -0,0 +1 @@ +[{"Horns & Hooves": -5100, "Pigbank": -100000, "Federates & Co": -100450, "Employer": 49000, "Swineld Fancy Flight": 97000, "Shavermier Inc": 49000, "Confederat & Co": 990000.1}, {"average_profit": 296250.025}] \ No newline at end of file diff --git a/lesson_5/hometask/employeers_salaries.txt b/lesson_5/hometask/employeers_salaries.txt new file mode 100644 index 0000000..9b0c1b5 --- /dev/null +++ b/lesson_5/hometask/employeers_salaries.txt @@ -0,0 +1,11 @@ +Иванов 23543.12 +Петров 13749.32 +Сидоров 31500.48 +Козлов 11111.11 +Псянин 100000.11 +Собакин 19999.99 +Синяков 20000.99 +Косяков 50000.55 +Распиляев 150000.65 +Пукин 160000.99 +Свинятин 40000.10 \ No newline at end of file diff --git a/lesson_5/hometask/get_file_by_files_list.py b/lesson_5/hometask/get_file_by_files_list.py new file mode 100644 index 0000000..d04fd04 --- /dev/null +++ b/lesson_5/hometask/get_file_by_files_list.py @@ -0,0 +1,51 @@ +import os + +def get_number_by_string(string_number: str): + """ + Функция преобразования строки к какому-либо числовому формату + + :param string_number: число в строковом виде + :return: число в числовом формате + """ + try: + return int(string_number) + except ValueError: + # если и тут ошибка, пробрасываем во внешний код + return float(string_number) + +def get_file_by_current_folder(interested_dir='.') -> str: + """ + Функция взаимодейcтвия с командной строкой + Исключительно консольная функция для моих нужд + Выводит список файлов в текущей директории + Позволяет выбрать индекс понравившегося файла + + :param interested_dir: директория поиска файла + :return: адрес файла с названием файла + """ + + files_list = os.listdir() + + if not os.path.isdir(interested_dir): + raise NotADirectoryError(f"Input dir {interested_dir} is non existing dir") + # удалим не "не файлы" из списка файлов + for file in files_list: + if not os.path.isfile(file): + files_list.remove(file) + array_len = len(files_list) + + # выведем файлы, которые пользователь может выбрать + print('Files for choose:') + for index, file in enumerate(files_list): + print(f"{index} or {index - array_len} : {file}") + + # Упорно запрашиваем индекс интересующего файла + while True: + try: + return os.path.join(interested_dir, files_list[int(input("Input the need file index >>>"))]) + except ValueError: + print("Uncorrect input") + continue + except IndexError: + print("Uncorrect file index") + continue diff --git a/lesson_5/hometask/lessons.txt b/lesson_5/hometask/lessons.txt new file mode 100644 index 0000000..74f727b --- /dev/null +++ b/lesson_5/hometask/lessons.txt @@ -0,0 +1,4 @@ +Информатика: 100(л) 50(пр) 20(лаб). +Физика: 30(л) — 10(лаб) +Физкультура: — 30(пр) — +Эритрейский язык: — — — \ No newline at end of file diff --git a/lesson_5/hometask/new_numbers_file.txt b/lesson_5/hometask/new_numbers_file.txt new file mode 100644 index 0000000..a0199e5 --- /dev/null +++ b/lesson_5/hometask/new_numbers_file.txt @@ -0,0 +1,4 @@ +Один — 1 +Два — 2 +Четыре — 4 +Три — 3 diff --git a/lesson_5/hometask/numeric_file.txt b/lesson_5/hometask/numeric_file.txt new file mode 100644 index 0000000..79579d0 --- /dev/null +++ b/lesson_5/hometask/numeric_file.txt @@ -0,0 +1 @@ +53.2 32.2 -3 3 \ No newline at end of file diff --git a/lesson_5/hometask/task_1.py b/lesson_5/hometask/task_1.py new file mode 100644 index 0000000..764b9e9 --- /dev/null +++ b/lesson_5/hometask/task_1.py @@ -0,0 +1,16 @@ +# Создать программно файл в текстовом формате, +# записать в него построчно данные, вводимые пользователем. +# Об окончании ввода данных свидетельствует пустая строка. + +# Файл будет создан в любом случае +# Даже если вводить уже ничего не хочется +with open("task_1_file.txt", "w") as task_file: + while True: + temp_string = input("Input user string to file >>>") + if temp_string == "": + break + try: + task_file.write(temp_string+'\n') + except FileNotFoundError: + print("Unable to process file in unexisting directory") + exit() diff --git a/lesson_5/hometask/task_1_file.txt b/lesson_5/hometask/task_1_file.txt new file mode 100644 index 0000000..71b272b --- /dev/null +++ b/lesson_5/hometask/task_1_file.txt @@ -0,0 +1,4 @@ +run_gun bababa;banana bobama,meor; +banana;her:mer? mer! +eat grass cowb +monker@chvonker.sru diff --git a/lesson_5/hometask/task_2.py b/lesson_5/hometask/task_2.py new file mode 100644 index 0000000..c2badfb --- /dev/null +++ b/lesson_5/hometask/task_2.py @@ -0,0 +1,29 @@ +# Создать текстовый файл (не программно), сохранить в нем несколько строк, +# выполнить подсчет количества строк, количества слов в каждой строке. +import get_file_by_files_list as my_add_func + + +def designificate_string(origin: str) -> str: + """ + Функция заменяет "несловесные" символы из строки на пробелы + + :param origin: исходная строка с кучей символов + :return: строка с пробелами вместо "несловесных" символов + """ + bad_symbols_list = ('.', ',', '?', '!', ';', ':', '"', "'", '\\', '|', '/', '(', ')') + for bad_symbol in bad_symbols_list: + origin = origin.replace(bad_symbol, ' ') + return origin + + +count_lines = 0 +count_strings = [] +# Какой файл выбрать - решает пользователь +with open(my_add_func.get_file_by_current_folder(), "r") as reading_file: + for fileline in reading_file: + count_lines += 1 + count_strings.append(len(designificate_string(fileline).split())) + +print(f"Overall lines count is {count_lines}") +for current_count, current_word_number in enumerate(count_strings, 1): + print(f"{current_count} : word count is {current_word_number}") diff --git a/lesson_5/hometask/task_3.py b/lesson_5/hometask/task_3.py new file mode 100644 index 0000000..f53b180 --- /dev/null +++ b/lesson_5/hometask/task_3.py @@ -0,0 +1,27 @@ +# Создать текстовый файл (не программно), +# построчно записать фамилии сотрудников и величину их окладов (не менее 10 строк). +# Определить, кто из сотрудников имеет оклад менее 20 тыс., вывести фамилии этих сотрудников. +# Выполнить подсчет средней величины дохода сотрудников. +# **Пример файла:** +# +# Иванов 23543.12 +# Петров 13749.32 + +import get_file_by_files_list as my_add_func + +employee_salary_dict = {} + +with open(my_add_func.get_file_by_current_folder(), "r") as reading_file: + for fileline in reading_file: + try: + employee, salary, *_ = fileline.split() + employee_salary_dict[employee] = float(salary) + except ValueError: + print(f"uncorrect value catched: {employee} : {salary}") + exit() + +for employee, salary in employee_salary_dict.items(): + if salary < 20000.0: + print(f"{employee} has a salary {salary} which less than 20000") + +print(f"Average employees salary is {round(sum(employee_salary_dict.values()) / len(employee_salary_dict), 2)}") diff --git a/lesson_5/hometask/task_4.py b/lesson_5/hometask/task_4.py new file mode 100644 index 0000000..25e0d4f --- /dev/null +++ b/lesson_5/hometask/task_4.py @@ -0,0 +1,31 @@ +# Создать (не программно) текстовый файл со следующим содержимым: +# +# One — 1 +# Two — 2 +# Three — 3 +# Four — 4 +# +# Необходимо написать программу, открывающую файл на чтение и считывающую построчно данные. +# При этом английские числительные должны заменяться на русские. +# Новый блок строк должен записываться в новый текстовый файл. +import get_file_by_files_list as my_add_func + +numbers_dict = {} +russian_numbers_dict = {1: 'Один', 2: 'Два', 3: 'Три', 4: 'Четыре', 10: 'Десять'} +final_filename = 'new_numbers_file.txt' + +with open(my_add_func.get_file_by_current_folder(), "r") as reading_file: + for fileline in reading_file: + try: + string_number, _, number, *_ = fileline.split() + numbers_dict[int(number)] = string_number + except ValueError: + print(f"uncorrect value catched: {string_number} - {number}") + exit() + +with open(final_filename, 'w') as writing_file: + for number, string_number in numbers_dict.items(): + # Если не будет значения в словаре российских соответствий + # то лучше вставить английский вариант, чем ничего + print(f"{russian_numbers_dict.get(number, string_number)} — {number}", file=writing_file) +# writing_file.write(f"{russian_numbers_dict.get(number, string_number)} — {number}\n") diff --git a/lesson_5/hometask/task_5.py b/lesson_5/hometask/task_5.py new file mode 100644 index 0000000..ef9896f --- /dev/null +++ b/lesson_5/hometask/task_5.py @@ -0,0 +1,33 @@ +# Создать (программно) текстовый файл, записать в него программно набор чисел, +# разделенных пробелами. +# Программа должна подсчитывать сумму чисел в файле и выводить ее на экран. +import get_file_by_files_list as my_add_func + +# Создаём файл, заполняем, потом парсим его и выводим сумму чисел + +str_number_list = [] +final_numeric_file_name = 'numeric_file.txt' + +for element in input("Введите набор чисел через пробелы >>>").split(): + # нужны только числа + try: + str_number_list.append(str(my_add_func.get_number_by_string(element))) + except ValueError: + continue + +# Запишем цифры в файл +with open(final_numeric_file_name, 'w') as num_file: + num_file.write(' '.join(str_number_list)) + print(f"numbers writes to file {num_file.name}") + +# Посчитаем сумму цифр +with open(my_add_func.get_file_by_current_folder(), "r") as reading_file: + numbers_sum = 0 + for line in reading_file: + for element in line.split(): + # суммируются элементы, которые приводятся к числу + try: + numbers_sum += my_add_func.get_number_by_string(element) + except ValueError: + continue + print(f"Sum of numbers in file {reading_file.name} is {numbers_sum}") \ No newline at end of file diff --git a/lesson_5/hometask/task_6.py b/lesson_5/hometask/task_6.py new file mode 100644 index 0000000..689d2b5 --- /dev/null +++ b/lesson_5/hometask/task_6.py @@ -0,0 +1,29 @@ +# Необходимо создать (не программно) текстовый файл, +# где каждая строка описывает учебный предмет и наличие +# лекционных, практических и лабораторных занятий по этому предмету и их количество. +# Важно, чтобы для каждого предмета не обязательно были все типы занятий. +# Сформировать словарь, содержащий название предмета и общее количество занятий по нему. +# Вывести словарь на экран. +# +# **Примеры строк файла:** +# Информатика: 100(л) 50(пр) 20(лаб). +# Физика: 30(л) — 10(лаб) +# Физкультура: — 30(пр) — +# **Пример словаря:** +# {“Информатика”: 170, “Физика”: 40, “Физкультура”: 30} +import get_file_by_files_list as my_add_func +import re + +science_dict = dict() + +# ошибки здесь не обрабатываю. Введено не то - ну что ж +with open(my_add_func.get_file_by_current_folder(), "r") as reading_file: + for line in reading_file: + science_name, others = line.split(":") + # только цифры + num_sum = 0 + # воспользуемся регулярными выражениями. Нужны только цифры + for num in ' '.join(re.split('[^\d]', others)).split(): + num_sum += my_add_func.get_number_by_string(num) + science_dict[science_name] = num_sum +print(f"Final dict is {science_dict}") diff --git a/lesson_5/hometask/task_7.py b/lesson_5/hometask/task_7.py new file mode 100644 index 0000000..f68c7a4 --- /dev/null +++ b/lesson_5/hometask/task_7.py @@ -0,0 +1,71 @@ +# Cоздать вручную и заполнить несколькими строками текстовый файл, +# в котором каждая строка должна содержать данные о фирме: +# название, форма собственности, выручка, издержки. +# +# **Пример строки файла:**firm_1 ООО 10000 5000. +# +# Необходимо построчно прочитать файл, вычислить прибыль каждой компании, +# а также среднюю прибыль. Если фирма получила убытки, в расчет средней прибыли ее не включать. +# +# Далее реализовать список. Он должен содержать словарь с фирмами и их прибылями, +# а также словарь со средней прибылью. Если фирма получила убытки, +# также добавить ее в словарь (со значением убытков). +# +# **Пример списка:**[{“firm_1”: 5000, “firm_2”: 3000, “firm_3”: 1000}, {“average_profit”: 2000}]. +# +# Итоговый список сохранить в виде json-объекта в соответствующий файл. +# +# **Пример json-объекта:** +# ` [{"firm_1": 5000, "firm_2": 3000, "firm_3": 1000}, {"average_profit": 2000}] ` +# +# **Подсказка:**использовать менеджер контекста. + +import json +import get_file_by_files_list as my_add_func + +# заготовка списка словарей с информацией о прибыльности фирм и средней прибыльности +# убытки в словарь средней прибыли не войдут +firm_list = [{}, {"average_profit": 0}] +firms_dict = firm_list[0] +firms_common_dict = firm_list[1] + + +def calculate_recurrent_average(new_value: float, avg: float, count: int) -> float: + """ + Расчёт среднего значения по рекуррентной формуле + avg_n = (avg_n-1 *(n-1) + an)/n + + :param new_value: новое значение, an + :param avg: среднее значение на предыдущей итерации, avg_n-1 + :param count: номер итерации, n + :return: среднее на текущей итерации + """ + if count <= 0: + raise ValueError("Iteration count must be a positive!") + return (avg * (count - 1) + new_value) / count + + +with open(my_add_func.get_file_by_current_folder(), "r") as reading_file: + profitible_count = 0 + for line in reading_file: + try: + *firm_name_array, company_form, revenue, costs = line.split() + revenue = my_add_func.get_number_by_string(revenue) + costs = my_add_func.get_number_by_string(costs) + except ValueError: + print(f"Unable to parse line {line}") + continue + firm_name = ' '.join(firm_name_array) + profitable = revenue - costs + firms_dict[firm_name] = profitable + if profitable < 0: + continue + profitible_count += 1 + firms_common_dict["average_profit"] = \ + calculate_recurrent_average(profitable, + firms_common_dict.get("average_profit", 0), + profitible_count) +print(firm_list) + +with open("company_dictlist.json", 'w') as json_file: + json.dump(firm_list, json_file) From 5a7194a01d138e5ac888536a6a8bb82907125aee Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Tue, 10 May 2022 13:51:24 +0300 Subject: [PATCH 06/10] Hometask 6 complete. Atention! Task 1 has a 2 realization. --- lesson_6/hometask/task_1.py | 43 +++++++++++ lesson_6/hometask/task_1_another.py | 62 ++++++++++++++++ lesson_6/hometask/task_2.py | 47 ++++++++++++ lesson_6/hometask/task_3.py | 56 +++++++++++++++ lesson_6/hometask/task_4.py | 108 ++++++++++++++++++++++++++++ lesson_6/hometask/task_5.py | 48 +++++++++++++ 6 files changed, 364 insertions(+) create mode 100644 lesson_6/hometask/task_1.py create mode 100644 lesson_6/hometask/task_1_another.py create mode 100644 lesson_6/hometask/task_2.py create mode 100644 lesson_6/hometask/task_3.py create mode 100644 lesson_6/hometask/task_4.py create mode 100644 lesson_6/hometask/task_5.py diff --git a/lesson_6/hometask/task_1.py b/lesson_6/hometask/task_1.py new file mode 100644 index 0000000..89d151d --- /dev/null +++ b/lesson_6/hometask/task_1.py @@ -0,0 +1,43 @@ +# Создать класс TrafficLight (светофор) и определить у него один атрибут color (цвет) +# и метод running (запуск). Атрибут реализовать как приватный. +# В рамках метода реализовать переключение светофора в режимы: +# красный, желтый, зеленый. +# Продолжительность первого состояния (красный) составляет 7 секунд, +# второго (желтый) — 2 секунды, третьего (зеленый) — на ваше усмотрение. +# Переключение между режимами должно осуществляться только в указанном порядке +# (красный, желтый, зеленый). +# Проверить работу примера, создав экземпляр и вызвав описанный метод. +# +# Задачу можно усложнить, реализовав проверку порядка режимов, +# и при его нарушении выводить соответствующее сообщение и завершать скрипт. + +# Задание абстрактное, конечно) +# Переключение между всеми режимами автоматически или пользователь задаёт текущий режим??? +# Если автоматически, то какого типа проверка и зачем она в принципе? +# Если пользователь задаёт текущий режим, то проверка нужна. Но зачем задержки?) И какой тогда это светофор? +# Нужен ли бесконечный цикл? Или цикл, прерывающийся по какому-либо условию? По какому условию? +# Разве не зелёный, желтый, красный?? + +import time + + +class TrafficLight: + __color: str + + def running(self): + self.__color = "red" + print(self.__color) + time.sleep(7) + self.__color = "yellow" + print(self.__color) + time.sleep(2) + self.__color = "green" + print(self.__color) + time.sleep(4) + + +if __name__ == "__main__": + obj = TrafficLight() + obj.running() + obj.running() + print("Thats all!") diff --git a/lesson_6/hometask/task_1_another.py b/lesson_6/hometask/task_1_another.py new file mode 100644 index 0000000..181ea0b --- /dev/null +++ b/lesson_6/hometask/task_1_another.py @@ -0,0 +1,62 @@ +# Создать класс TrafficLight (светофор) и определить у него один атрибут color (цвет) +# и метод running (запуск). Атрибут реализовать как приватный. +# В рамках метода реализовать переключение светофора в режимы: +# красный, желтый, зеленый. +# Продолжительность первого состояния (красный) составляет 7 секунд, +# второго (желтый) — 2 секунды, третьего (зеленый) — на ваше усмотрение. +# Переключение между режимами должно осуществляться только в указанном порядке +# (красный, желтый, зеленый). +# Проверить работу примера, создав экземпляр и вызвав описанный метод. +# +# Задачу можно усложнить, реализовав проверку порядка режимов, +# и при его нарушении выводить соответствующее сообщение и завершать скрипт. + +# Задание абстрактное, конечно) +# Переключение между всеми режимами автоматически или пользователь задаёт текущий режим??? +# Если автоматически, то какого типа проверка и зачем она в принципе? +# Если пользователь задаёт текущий режим, то проверка нужна. Но зачем задержки?) И какой тогда это светофор? +# Нужен ли бесконечный цикл? Или цикл, прерывающийся по какому-либо условию? По какому условию? +# Разве не зелёный, желтый, красный?? + +import time +from itertools import cycle as it_tools_cycle + +traffic_modes = ('red', 'yellow', 'green') + + +class TrafficLight: + __color = "" + __traffic_modes_order = dict(zip(traffic_modes, [x for x in range(1, len(traffic_modes) + 1)])) + __traffic_modes_duration = dict(zip(traffic_modes, (7, 2, 4))) + + # проверка правильности последовательности + # ... -> red -> yellow -> green -> red -> yellow -> green -> red -> ... + # лучше через def. Хотя лямбда быстрее. Ну и мне интересно попробовать именно так) + check_order = lambda current, previous: (current - previous) % 3 == 1 + + def running(self, mode: str): + if mode not in traffic_modes: + raise ValueError("Unexpected traffic mode") + if not self.__color: + self.__color = mode + elif not TrafficLight.check_order(self.__traffic_modes_order[mode], + self.__traffic_modes_order[self.__color]): + string = f"Uncorrect traffic mode order! Previous {self.__color}, you need {mode}" + raise ValueError(string) + self.__color = mode + print(self.__color) + time.sleep(self.__traffic_modes_duration[self.__color]) + + +if __name__ == "__main__": + obj = TrafficLight() + my_max_count = 2 + obj.running("green") + mode_gen = it_tools_cycle(traffic_modes) + for count in range(my_max_count*len(traffic_modes)): + obj.running(mode_gen.__next__()) + obj.running("red") + obj.running("yellow") + # а тут порядок нарущен! + obj.running("red") + print("Thats all!") diff --git a/lesson_6/hometask/task_2.py b/lesson_6/hometask/task_2.py new file mode 100644 index 0000000..374c358 --- /dev/null +++ b/lesson_6/hometask/task_2.py @@ -0,0 +1,47 @@ +# Реализовать класс Road (дорога), в котором определить атрибуты: +# length (длина), width (ширина). +# Значения данных атрибутов должны передаваться при создании экземпляра класса. +# Атрибуты сделать защищенными. Определить метод расчета массы асфальта, +# необходимого для покрытия всего дорожного полотна. +# Использовать формулу: длина`*`ширина`*`масса асфальта для покрытия одного кв метра дороги асфальтом, +# толщиной в 1 см`*`число см толщины полотна. +# Проверить работу метода. +# +# **Например:** 20м`*`5000м`*`25кг`*`5см = 12500 т + +class Road: + _length: float + _width: float + + def __init__(self, length: float, width: float): + self._length = length if length > 0.0 else 0.0 + self._width = width if width > 0.0 else 0.0 + + def get_asphalt_mass(self, thickness: float = 5.0, mass_per_sm_sq_m: float = 25.0): + """ + Расчета массы асфальта, необходимого для покрытия всего дорожного полотна + + :param thickness: толщина полотна, см + :param mass_per_sm_sq_m: масса асфальта для покрытия одного кв метра + дороги асфальтом, толщиной в 1 см, кг/м**2*см + :return: массы асфальта, необходимого для покрытия всего дорожного полотна, кг + """ + return self._length * self._width * thickness * mass_per_sm_sq_m + + +if __name__ == "__main__": + universe_result_str = "Требуемая масса асфальта для толщины {thick} см и " \ + "массы {mass_per_vol} кг/м**2*см равна {mass} кг" + current_road = Road(length=float(input("Длина дороги >>>")), + width=float(input("Ширина дороги >>>"))) + thickness = float(input("Толщина дороги >>>")) + # масса асфальта для покрытия одного кв метра +- стандартизирована + print(universe_result_str.format(thick=thickness, + mass_per_vol=25, + mass=current_road.get_asphalt_mass(thickness))) + thickness = float(input("Толщина дороги >>>")) + mass_per_volume = float(input("Масса асфальта для покрытия одного кв метра " + "дороги асфальтом, толщиной в 1 см >>>")) + print(universe_result_str.format(thick=thickness, + mass_per_vol=mass_per_volume, + mass=current_road.get_asphalt_mass(thickness))) \ No newline at end of file diff --git a/lesson_6/hometask/task_3.py b/lesson_6/hometask/task_3.py new file mode 100644 index 0000000..9c39800 --- /dev/null +++ b/lesson_6/hometask/task_3.py @@ -0,0 +1,56 @@ +# Реализовать базовый класс Worker (работник), +# в котором определить атрибуты: +# name, surname, position (должность), income (доход). +# Последний атрибут должен быть защищенным и ссылаться на словарь, +# содержащий элементы: оклад и премия, например, {"wage": wage, "bonus": bonus}. +# Создать класс Position (должность) на базе класса Worker. +# В классе Position реализовать методы получения полного имени сотрудника (get_full_name) +# и дохода с учетом премии (get_total_income). +# Проверить работу примера на реальных данных +# (создать экземпляры класса Position, передать данные, +# проверить значения атрибутов, вызвать методы экземпляров). + +class Worker: + name: str + surname: str + position: str + _income = {"wage": float, "bonus": float} + + def __init__(self, name, surname): + self.name, self.surname = name, surname + + def set_income(self, wage: float, bonus: float = 0.0): + """ + Метод расчёта полной заработной платы. + Оклад не может быть отрицательным. + А вот премия может быть штрафом! + + :param wage: оклад + :param bonus: премия или штраф + :return: полная заработная плата + """ + self._income["wage"], self._income["bonus"] = wage if wage >= 0.0 else 0.0, bonus + + +class Position(Worker): + def __init__(self, name: str, surname: str, position: str): + super().__init__(name, surname) + self.position = position + + def get_full_name(self): + return f"{self.name} {self.surname}" + + def get_total_income(self): + if (type(self._income["wage"]) is type) or (self._income["bonus"] is type): + raise ValueError("wage and bonus are not setted!") + return self._income["wage"] + self._income["bonus"] + + +if __name__ == "__main__": + *drudge_name, drudge_surname = input("Enter person name, surname >>> ").split() + drudge_name = " ".join(drudge_name) + drudge = Position(name=drudge_name, surname=drudge_surname, position=input("Input position title >>>")) + wage = float(input(f"Enter the {drudge.position} wage >>> ")) + bonus = float(input(f"Enter the {drudge.position} bonus >>> ")) + drudge.set_income(float(wage), float(bonus)) + print(f"{drudge.get_full_name()} is {drudge.position} with salary {drudge.get_total_income()}.") diff --git a/lesson_6/hometask/task_4.py b/lesson_6/hometask/task_4.py new file mode 100644 index 0000000..89b6ef6 --- /dev/null +++ b/lesson_6/hometask/task_4.py @@ -0,0 +1,108 @@ +# Реализуйте базовый класс Car. +# У данного класса должны быть следующие атрибуты: +# speed, color, name, is_police (булево). +# А также методы: go, stop, turn(direction), +# которые должны сообщать, что машина поехала, остановилась, повернула (куда). +# Опишите несколько дочерних классов: +# TownCar, SportCar, WorkCar, PoliceCar. +# Добавьте в базовый класс метод show_speed, +# который должен показывать текущую скорость автомобиля. +# Для классов TownCar и WorkCar переопределите метод show_speed. +# При значении скорости свыше 60 (TownCar) и 40 (WorkCar) +# должно выводиться сообщение о превышении скорости. +# Создайте экземпляры классов, передайте значения атрибутов. +# Выполните доступ к атрибутам, выведите результат. +# Выполните вызов методов и также покажите результат. + +turn_turple = ("налево", "направо", "назад") + + +class Car: + speed: float + color: str + name: str = "" + is_police: bool = False + + def go(self) -> str: + return f"Машина {self.name} поехала" + + def stop(self) -> str: + # можно добавить time.sleep со временем, соответствующем тормозному пути + self.speed = 0.0 + return f"Машина {self.name} остановилась" + + def turn(self, direction: str) -> str: + if direction in turn_turple: + return f"Машина {self.name} повернула {direction}" + else: + return f"Манёвр {direction} недоступен, машина {self.name} движется без изменений" + + def show_speed(self) -> str: + return f"Текущая скорость {self.name} {self.speed} км/ч" + + def get_car_type_info(self) -> str: + return f'{self.color} {self.name} is {"" if self.is_police else "not "}a police car' + + +class TownCar(Car): + _extra_speed = 60 + + def show_speed(self) -> str: + if self.speed > self._extra_speed: + return f"{super().show_speed()} превышает лимит в {self._extra_speed} км/ч!" + else: + # согласно документации, в данном контексте == super() + return super(TownCar, self).show_speed() + + +class SportCar(Car): + pass + + +class WorkCar(Car): + _extra_speed = 40 + + def show_speed(self) -> str: + if self.speed > self._extra_speed: + return f"{super().show_speed()} км/ч превышает лимит в {self._extra_speed} км/ч!" + else: + return super(WorkCar, self).show_speed() + + +class PoliceCar(Car): + def __init__(self): + self.is_police = True + super().__init__() + + +if __name__ == "__main__": + city_car = TownCar() + speedy_car = SportCar() + drudge_car = WorkCar() + cop_car = PoliceCar() + + city_car.name = "Toyota" + speedy_car.name = "Porsche" + drudge_car.name = "Renault" + cop_car.name = "Dodge" + + city_car.speed = 70.0 + drudge_car.speed = 40.0 + speedy_car.speed = 100.0 + speedy_car.color = "Red" + city_car.color = "Orange" + drudge_car.color = "White" + cop_car.color = "Police colored" + + print(city_car.get_car_type_info()) + print(drudge_car.get_car_type_info()) + print(speedy_car.get_car_type_info()) + print(cop_car.get_car_type_info()) + + print(drudge_car.show_speed()) + print(cop_car.go()) + print(speedy_car.show_speed()) + print(speedy_car.stop()) + print(speedy_car.show_speed()) + print(city_car.turn("налево")) + print(cop_car.turn("напрямо")) diff --git a/lesson_6/hometask/task_5.py b/lesson_6/hometask/task_5.py new file mode 100644 index 0000000..b018fe2 --- /dev/null +++ b/lesson_6/hometask/task_5.py @@ -0,0 +1,48 @@ +# Реализовать класс Stationery (канцелярская принадлежность). +# Определить в нем атрибут title (название) и метод draw (отрисовка). +# Метод выводит сообщение “Запуск отрисовки.” +# Создать три дочерних класса Pen (ручка), Pencil (карандаш), Handle (маркер). +# В каждом из классов реализовать переопределение метода draw. +# Для каждого из классов метод должен выводить уникальное сообщение. +# Создать экземпляры классов и проверить, что выведет описанный метод для каждого экземпляра. + +class Stationery: + _title: str + + def draw(self): + return "Запуск отрисовки." + + +class Pen(Stationery): + def __init__(self): + self._title = "Ручка" + + def draw(self): + return f"{super().draw()} {self._title} используется для отрисовки." + + +class Pencil(Stationery): + def __init__(self): + self._title = "Карандаш" + + def draw(self): + return f"{super().draw()} {self._title} используется для отрисовки." + + +class Handle(Stationery): + def __init__(self): + self._title = "Маркер" + + def draw(self): + return f"{super().draw()} {self._title} используется для отрисовки." + + +if __name__ == "__main__": + something = Stationery() + pen = Pen() + pencil = Pencil() + handle = Handle() + print(something.draw()) + print(pen.draw()) + print(pencil.draw()) + print(handle.draw()) From ca9f6451faae0998b14cc3bef9e3df31b3373c54 Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Fri, 13 May 2022 21:23:05 +0300 Subject: [PATCH 07/10] Hometask 7 complete --- lesson_7/hometask/task_1.py | 72 +++++++++++++++++++++++ lesson_7/hometask/task_2.py | 76 ++++++++++++++++++++++++ lesson_7/hometask/task_3.py | 111 ++++++++++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 lesson_7/hometask/task_1.py create mode 100644 lesson_7/hometask/task_2.py create mode 100644 lesson_7/hometask/task_3.py diff --git a/lesson_7/hometask/task_1.py b/lesson_7/hometask/task_1.py new file mode 100644 index 0000000..1ecdc28 --- /dev/null +++ b/lesson_7/hometask/task_1.py @@ -0,0 +1,72 @@ +# Реализовать класс Matrix (матрица). Обеспечить перегрузку конструктора класса (метод __init__()), +# который должен принимать данные (список списков) для формирования матрицы. +# +# **Подсказка:** матрица — система некоторых математических величин, расположенных в виде прямоугольной схемы. +# **Примеры матриц:** см. в методичке. +# +# Следующий шаг — реализовать перегрузку метода __str__() для вывода матрицы в привычном виде. +# +# Далее реализовать перегрузку метода __add__() для реализации операции сложения двух объектов +# класса Matrix (двух матриц). Результатом сложения должна быть новая матрица. +# +# **Подсказка:** сложение элементов матриц выполнять поэлементно — первый элемент +# первой строки первой матрицы складываем с первым элементом первой строки второй матрицы и т.д. + +class Matrix: + def __init__(self, data): + # простейшая проверка. Все элементы не перебираем + # убеждаемся, что имеем дело со списком списков, как в задании изложено + # Пользователь может передать целое или простой список + # или список списков строк. Следует объяснить суть ошибки + try: + for elem in (x for list_1 in data for x in list_1): + if not (type(elem) is float or type(elem) is int): + raise TypeError + # вот эти ограничения не очевидны, но следуют из формулировки задания + if type(data) is not list: + raise TypeError + if type(data[0]) is not list: + raise TypeError + except TypeError: + raise ValueError("Expected data datatype is list of list of numbers") + self._inner_data = data + + def __str__(self): + return "\n".join(" ".join(str(x) for x in row) for row in self._inner_data) + + @property + def rows_count(self): + return len(self._inner_data) + + @property + def columns_count(self): + return len(self._inner_data[0]) + + def __add__(self, other): + if type(other) is not Matrix: + raise ValueError("Expected operands datatype is Matrix") + if self.rows_count != other.rows_count or self.columns_count != other.columns_count: + raise ValueError("Sizes of matrixes are not the same!") + new_matrix = list() + # доступ к защищенным членам класса - это плохо. + # Но это метод этого же класса! В данном контексте, приемлиемо. + for row_1, row_2 in zip(self._inner_data, other._inner_data): + new_matrix.append([el_1 + el_2 for el_1, el_2 in zip(row_1, row_2)]) + return Matrix(new_matrix) + + +if __name__ == "__main__": + matr_1 = Matrix([[1, 2, 3], [4, 5, 6.0]]) + matr_2 = Matrix([[1, 2, 3], [4, 5, 6]]) + res_matr = matr_1 + matr_2 + print(matr_1) + print("+") + print(matr_2) + print("=") + print(res_matr) + print(type(res_matr)) + try: + # print(Matrix([1, 2, 3])) + print(Matrix([[1, 2, 3], [4, 5, '6']])) + except ValueError as value_error: + print(value_error) diff --git a/lesson_7/hometask/task_2.py b/lesson_7/hometask/task_2.py new file mode 100644 index 0000000..3e88df7 --- /dev/null +++ b/lesson_7/hometask/task_2.py @@ -0,0 +1,76 @@ +# Реализовать проект расчета суммарного расхода ткани на производство одежды. +# Основная сущность (класс) этого проекта — одежда, +# которая может иметь определенное название. +# К типам одежды в этом проекте относятся пальто и костюм. +# У этих типов одежды существуют параметры: +# размер (для пальто) и рост (для костюма). +# Это могут быть обычные числа: V и H, соответственно. +# +# Для определения расхода ткани по каждому типу одежды использовать формулы: +# для пальто (V/6.5 + 0.5), для костюма (2`*`H + 0.3). +# Проверить работу этих методов на реальных данных. +# +# Реализовать общий подсчет расхода ткани. +# Проверить на практике полученные на этом уроке знания: +# реализовать абстрактные классы для основных классов проекта, +# проверить на практике работу декоратора @property. + +# Общий подсчёт тканей?? Это ткань пальто+ткань костюм???)))) + +import abc + + +class Clothes(abc.ABC): + def __init__(self, name: str): + self._name = name + + @property + def name(self): + return self._name + + @abc.abstractmethod + def cloth_consumption(self): + pass + + +class Coat(Clothes): + def __init__(self, size: float, name: str = "Coat"): + self.cloth_consumption = size + super().__init__(name) + + @property + def cloth_consumption(self): + return round(self._size / 6.5 + 0.5, 3) + + @cloth_consumption.setter + def cloth_consumption(self, value): + if value > 0: + self._size = value + + +class Suit(Clothes): + def __init__(self, height: float, name: str = "Suit"): + if height > 0: + self._height = height + super().__init__(name) + + @property + def cloth_consumption(self): + return round(2 * self._height + 0.3, 3) + + @cloth_consumption.setter + def cloth_consumption(self, value): + if value > 0: + self._height = value + + +if __name__ == "__main__": + cloth_list = [Coat(48), Suit(1.73, "Smocking")] + cloth_str = "It needs {consumption} of cloth to make a {name}" + for clothe in cloth_list: + print(cloth_str.format(consumption=clothe.cloth_consumption, name=clothe.name)) + cloth_list[0].cloth_consumption = 52 + # cloth_list.append(Clothes()) + + for clothe in cloth_list: + print(cloth_str.format(consumption=clothe.cloth_consumption, name=clothe.name)) diff --git a/lesson_7/hometask/task_3.py b/lesson_7/hometask/task_3.py new file mode 100644 index 0000000..7dbe0a3 --- /dev/null +++ b/lesson_7/hometask/task_3.py @@ -0,0 +1,111 @@ +# Реализовать программу работы с органическими клетками, состоящими из ячеек. +# Необходимо создать класс Клетка. +# В его конструкторе инициализировать параметр, +# соответствующий количеству ячеек клетки (целое число). +# В классе должны быть реализованы методы перегрузки арифметических операторов: +# сложение (**add**()), вычитание (**sub**()), +# умножение (**mul**()), деление (**truediv**()). +# Данные методы должны применяться только к клеткам и +# выполнять увеличение, уменьшение, умножение и целочисленное +# (с округлением до целого) деление клеток, соответственно. +# +# **Сложение.**Объединение двух клеток. +# При этом число ячеек общей клетки должно +# равняться сумме ячеек исходных двух клеток. +# **Вычитание.**Участвуют две клетки. +# Операцию необходимо выполнять только если разность +# количества ячеек двух клеток больше нуля, +# иначе выводить соответствующее сообщение. +# **Умножение.**Создается общая клетка из двух. +# Число ячеек общей клетки определяется как +# произведение количества ячеек этих двух клеток. +# **Деление.**Создается общая клетка из двух. +# Число ячеек общей клетки определяется как +# целочисленное деление количества ячеек этих двух клеток. +# В классе необходимо реализовать метод make_order(), +# принимающий экземпляр класса и количество ячеек в ряду. +# Данный метод позволяет организовать ячейки по рядам. +# Метод должен возвращать строку вида`*****\n*****\n*****`..., +# где количество ячеек между`\n`равно переданному аргументу. +# Если ячеек на формирование ряда не хватает, то в последний ряд записываются все оставшиеся. +# Например, количество ячеек клетки равняется 12, +# количество ячеек в ряду — 5. Тогда метод make_order() +# вернет строку:`*****\n*****\n**`. +# Или, количество ячеек клетки равняется 15, +# количество ячеек в ряду — 5. Тогда метод make_order() вернет строку:`*****\n*****\n*****`. + +class Organic_Cell: + def __init__(self, cellure_number: int): + if cellure_number <= 0: + raise ValueError("cellure number must be a positive!") + self._cellure_number = cellure_number + + @property + def cellure_number(self): + return self._cellure_number + + def __raise_if_not_cell(self, object): + if type(object) is not Organic_Cell: + raise TypeError("Unexpected operand type; Organic_Cell object expected") + + def __add__(self, other): + self.__raise_if_not_cell(other) + return Organic_Cell(self._cellure_number + other.cellure_number) + + def __sub__(self, other): + self.__raise_if_not_cell(other) + if self._cellure_number <= other.cellure_number: + raise ValueError("Resulting cellure number less or equal zero!") + return Organic_Cell(self._cellure_number - other.cellure_number) + + def __mul__(self, other): + self.__raise_if_not_cell(other) + return Organic_Cell(self._cellure_number * other.cellure_number) + + def __truediv__(self, other): + self.__raise_if_not_cell(other) + return Organic_Cell(self._cellure_number // other.cellure_number) + + def __str__(self): + return "*" * self._cellure_number + + def __repr__(self): + return self.__str__() + + def make_order(self, cellure_in_row: int): + if cellure_in_row <= 0: + raise ValueError("Cellure in row number must be a positive!") + rows, lost_cells = divmod(self._cellure_number, cellure_in_row) + + return "\n".join([f"{'*' * cellure_in_row}" + for i in range(rows)]) + (f'\n{"*" * lost_cells}' + if lost_cells > 0 else "") + + +if __name__ == "__main__": + cells = (Organic_Cell(12), Organic_Cell(15)) + for cell in cells: + print(cell.make_order(5)) + print('\n') + + print(f'{cells[0]} + {cells[1]} = {cells[0] + cells[1]}') + print(f'{cells[0].cellure_number} + {cells[1].cellure_number} = {(cells[0] + cells[1]).cellure_number}') + + try: + print(f'{cells[0]} - {cells[1]} = {cells[0] - cells[1]}') + except ValueError as type_error: + print(f'\n{type_error}') + + print(f'\n{cells[1]} - {cells[0]} = {cells[1] - cells[0]}') + print(f'{cells[1].cellure_number} - {cells[0].cellure_number} = {(cells[1] - cells[0]).cellure_number}') + + print(f'\n{cells[0]}\n*\n{cells[1]}\n=\n{(cells[0] * cells[1]).make_order(cells[0].cellure_number)}') + print(f'{cells[0].cellure_number} * {cells[1].cellure_number} = {(cells[0] * cells[1]).cellure_number}') + + try: + print(f'{cells[0]} / {cells[1]} = {cells[0] / cells[1]}') + except ValueError as value_error: + print(f'\n{value_error}') + + print(f'\n{cells[1]} / {cells[0]} = {cells[1] / cells[0]}') + print(f'{cells[1].cellure_number} / {cells[0].cellure_number} = {(cells[1] / cells[0]).cellure_number}') From 7359e0a90b20f1e9184041cabe077dfe794b6e82 Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Sat, 14 May 2022 10:05:51 +0300 Subject: [PATCH 08/10] Some tiny changes --- lesson_7/hometask/task_1.py | 1 - lesson_7/hometask/task_2.py | 27 ++++++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lesson_7/hometask/task_1.py b/lesson_7/hometask/task_1.py index 1ecdc28..bc9d6fc 100644 --- a/lesson_7/hometask/task_1.py +++ b/lesson_7/hometask/task_1.py @@ -14,7 +14,6 @@ class Matrix: def __init__(self, data): - # простейшая проверка. Все элементы не перебираем # убеждаемся, что имеем дело со списком списков, как в задании изложено # Пользователь может передать целое или простой список # или список списков строк. Следует объяснить суть ошибки diff --git a/lesson_7/hometask/task_2.py b/lesson_7/hometask/task_2.py index 3e88df7..a593dbb 100644 --- a/lesson_7/hometask/task_2.py +++ b/lesson_7/hometask/task_2.py @@ -32,18 +32,27 @@ def name(self): def cloth_consumption(self): pass + @abc.abstractmethod + def cloth_size(self, value): + pass + class Coat(Clothes): def __init__(self, size: float, name: str = "Coat"): - self.cloth_consumption = size - super().__init__(name) + if size > 0: + self._size = size + super().__init__(name) @property def cloth_consumption(self): return round(self._size / 6.5 + 0.5, 3) - @cloth_consumption.setter - def cloth_consumption(self, value): + @property + def cloth_size(self): + return self._size + + @cloth_size.setter + def cloth_size(self, value): if value > 0: self._size = value @@ -58,8 +67,12 @@ def __init__(self, height: float, name: str = "Suit"): def cloth_consumption(self): return round(2 * self._height + 0.3, 3) - @cloth_consumption.setter - def cloth_consumption(self, value): + @property + def cloth_size(self): + return self._height + + @cloth_size.setter + def cloth_size(self, value): if value > 0: self._height = value @@ -69,7 +82,7 @@ def cloth_consumption(self, value): cloth_str = "It needs {consumption} of cloth to make a {name}" for clothe in cloth_list: print(cloth_str.format(consumption=clothe.cloth_consumption, name=clothe.name)) - cloth_list[0].cloth_consumption = 52 + cloth_list[0].cloth_size = 52 # cloth_list.append(Clothes()) for clothe in cloth_list: From c8e672dda04d896815332fa3ca395a1fce3753c0 Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Sat, 14 May 2022 10:19:14 +0300 Subject: [PATCH 09/10] =?UTF-8?q?I=20=D1=81hange=20my=20opinion.=20Name=20?= =?UTF-8?q?need=20otherwise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lesson_7/hometask/task_2.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lesson_7/hometask/task_2.py b/lesson_7/hometask/task_2.py index a593dbb..9117ff4 100644 --- a/lesson_7/hometask/task_2.py +++ b/lesson_7/hometask/task_2.py @@ -39,9 +39,8 @@ def cloth_size(self, value): class Coat(Clothes): def __init__(self, size: float, name: str = "Coat"): - if size > 0: - self._size = size - super().__init__(name) + self.cloth_size = size + super().__init__(name) @property def cloth_consumption(self): @@ -59,9 +58,8 @@ def cloth_size(self, value): class Suit(Clothes): def __init__(self, height: float, name: str = "Suit"): - if height > 0: - self._height = height - super().__init__(name) + self.cloth_size = height + super().__init__(name) @property def cloth_consumption(self): From 477322469eb699c96924571fbfd4114c26c5568c Mon Sep 17 00:00:00 2001 From: Mikhalev V Date: Wed, 18 May 2022 11:17:19 +0300 Subject: [PATCH 10/10] Hometask 8 complete --- lesson_8/hometask/common.py | 12 + lesson_8/hometask/task_1.py | 165 +++++++++++ lesson_8/hometask/task_2.py | 44 +++ lesson_8/hometask/task_3.py | 73 +++++ lesson_8/hometask/task_4_5_6_equipment.py | 321 ++++++++++++++++++++++ lesson_8/hometask/task_4_5_6_store.py | 226 +++++++++++++++ lesson_8/hometask/task_7.py | 116 ++++++++ 7 files changed, 957 insertions(+) create mode 100644 lesson_8/hometask/common.py create mode 100644 lesson_8/hometask/task_1.py create mode 100644 lesson_8/hometask/task_2.py create mode 100644 lesson_8/hometask/task_3.py create mode 100644 lesson_8/hometask/task_4_5_6_equipment.py create mode 100644 lesson_8/hometask/task_4_5_6_store.py create mode 100644 lesson_8/hometask/task_7.py diff --git a/lesson_8/hometask/common.py b/lesson_8/hometask/common.py new file mode 100644 index 0000000..a0f3c98 --- /dev/null +++ b/lesson_8/hometask/common.py @@ -0,0 +1,12 @@ +def get_number_by_string(string_number: str): + """ + Функция преобразования строки к какому-либо числовому формату + + :param string_number: число в строковом виде + :return: число в числовом формате + """ + try: + return int(string_number) + except ValueError: + # если и тут ошибка, пробрасываем во внешний код + return float(string_number) \ No newline at end of file diff --git a/lesson_8/hometask/task_1.py b/lesson_8/hometask/task_1.py new file mode 100644 index 0000000..aa026dc --- /dev/null +++ b/lesson_8/hometask/task_1.py @@ -0,0 +1,165 @@ +# Реализовать класс «Дата», функция-конструктор которого должна +# принимать дату в виде строки формата «день-месяц-год». +# В рамках класса реализовать два метода. +# Первый, с декоратором @classmethod, должен извлекать число, +# месяц, год и преобразовывать их тип к типу «Число». +# Второй, с декоратором @staticmethod, должен проводить валидацию числа, +# месяца и года (например, месяц — от 1 до 12). +# Проверить работу полученной структуры на реальных данных. + +# Что я не понял в задании: +# Зачем нужен метод класса? День,месяц, год - это именно изменяемые атрибуты класса, не объекта? +# Нужна ли валидация в методе класса? +# Если нет, то зачем вообще нужен именно метод класса, а не статический метод? +# Разве может класс хранить некорректные данные? +# Зачем нужен конструктор класса? Ведь дата живёт в самом классе, не объекте... +# Зачем генерировать все прочие объекты со старыми датами, характерными для класса через метод класса? +# Нужно ли вообще в объекте менять число, месяц, год? +# Что хранит именно объект? Строку? + +class Date: + _day: int + _month: int + _year: int + + def __init__(self, date: str): + # вообще, то, что в классе, то и в self + # так что, возможно, это излишне + # и в целом, мне не нравится вызов этого здесь + # класс - это класс, объект - это объект + # поэтому хорошо бы эту функцию сделать не методом класса! + self._day, self._month, self._year = self.get_year_month_day(date) + + @staticmethod + def leap_good_year(year: int) -> bool: + """ + Проверка на високосный год + + :param year: год, > 0 (в истории есть нюансы, но мы рассматриваем нашу эру) + :return: булево значение, True если високосный и False если не високосный + """ + if year < 0: + return False + if year % 100 == 0: + if year % 400 == 0: + return True + else: + return False + elif year % 4 == 0: + return True + + return False + + @staticmethod + def check_31_day_month(month: int) -> bool: + """ + Проверка, 31 день в месяце или нет + + :param month: месяц, положительное число от 1 до 13 + :return: булево True, если в месяце 31 день или + False, если не 31 день + """ + if month not in range(1, 13): + raise ValueError("Month need to be in range 1 to 12!") + + # признак нечётного месяца + is_odd = bool(month % 2) + return is_odd if (month <= 7) else not is_odd + + @staticmethod + def check_date_numbers(*, day: int, month: int, year: int) -> tuple: + """ + Проверка числа, месяца, года на валидность. + Значения задаются только с помощью именованных аргументов, + чтобы дорогой пользователь ничего не перепутал. + + :param day: день, 1-31 (но не всё так однозначно) + :param month: месяц, 1-12 + :param year: год, любое положительное число. + Хотя интерес может быть и к годам до нашей эры, здесь это не принимаем. + Да, мы оптимистично смотрим в будущее и не ограничиваемся 4мя цифрами. + :return: кортеж булевых значений по дню, месяцу и году. + """ + good_month, good_year = month in range(1, 13), year >= 0 + # максимальное количество дней, по-умолчанию самый максимум + max_days = 31 + + if good_month: + # Для февраля всё по-особому + if month == 2: + # прям максимум 29 дней + # но если год адекватный и не високосный, то 28 + max_days = (29, 28)[good_year and not Date.leap_good_year(year)] + else: + max_days = 31 if Date.check_31_day_month(month) else 30 + + return day in range(1, max_days + 1), good_month, good_year + + @classmethod + def get_year_month_day(cls: 'Date', date: str) -> tuple: + """ + Извлекает день, месяц, год из форматированной строки. + Также меняет соответствующие поля у передаваемого класса. + Если у строки не тот формат, будет выдана ошибка. + + :param cls: Класс (потомок) Date + :param date: форматированная строка даты "день-месяц-год" + :return: кортеж целых чисел день, месяц, год + """ + # хотел сделать проверку только формата строки, + # как сказано в задании, но смущает, что это - метод класса... + # Можно ли допускать, чтобы данные класса были некорректны??? + try: + day, month, year = date.split('-') + # В принципе, теперь можно не бояться отрицательных значений! + day, month, year = int(day), int(month), int(year) + except ValueError: + # Нужно более конкретное сообщение + raise ValueError('Uncorrect date format') + day_mark, month_mark, year_mark = \ + Date.check_date_numbers(day=day, month=month, year=year) + + # можно обработать иначе и не сосредотачиваться на ошибке! + def raise_valueerror_if_need(mark: bool, message: str): + if not mark: + raise ValueError(message) + + raise_valueerror_if_need(year_mark, "Uncorrect year value!") + raise_valueerror_if_need(month_mark, "Uncorrect month value!") + raise_valueerror_if_need(day_mark, "Uncorrect day value!") + # не знаю, зачем именно метод класса, а не статический метод + # это единственное предположение, больше мыслей нет + cls._day, cls._month, cls._year = day, month, year + # ну это для контроля и прочих удобств + return cls._day, cls._month, cls._year + + def __str__(self): + return f'{self._day} {self._month} {self._year}' + + +if __name__ == '__main__': + date_tuple = (Date("28-02-2020"), Date("30-04-23035")) + for cur_date in date_tuple: + print(cur_date) + try: + print(Date("32-13--5")) + except ValueError as value_err: + print(value_err) + try: + print(Date("32 13 5")) + except ValueError as value_err: + print(value_err) + print(Date.check_date_numbers(day=29, month=2, year=2024)) + print(Date.check_date_numbers(day=29, month=2, year=2022)) + print(Date.check_date_numbers(day=32, month=14, year=2022)) + print(Date.check_date_numbers(day=29, month=8, year=-5)) + try: + print(Date.get_year_month_day("32-05-20888")) + except ValueError as value_err: + print(value_err) + print(Date.get_year_month_day("31-05-2088")) + for cur_date in date_tuple: + print(cur_date) + # Достучимся до того, что запрещено... + # Специально не делал в классе property classmethod, эти данные защищены принципиально... + print(f'Date class day {Date._day} month {Date._month} year {Date._year}') diff --git a/lesson_8/hometask/task_2.py b/lesson_8/hometask/task_2.py new file mode 100644 index 0000000..8033842 --- /dev/null +++ b/lesson_8/hometask/task_2.py @@ -0,0 +1,44 @@ +# Создайте собственный класс-исключение, обрабатывающий ситуацию деления на нуль. +# Проверьте его работу на данных, вводимых пользователем. +# При вводе пользователем нуля в качестве делителя программа +# должна корректно обработать эту ситуацию и не завершиться с ошибкой. +import decimal +import common + + +class MyZeroDivisionError(ZeroDivisionError): + def __init__(self, numerator, denominator): + if MyZeroDivisionError.check_numeric(numerator) and \ + MyZeroDivisionError.check_numeric(denominator): + self._numerator = numerator + self._denominator = denominator + super().__init__(numerator, denominator) + + @staticmethod + def check_numeric(number): + return isinstance(number, int) or \ + isinstance(number, float) or \ + isinstance(number, decimal.Decimal) + + def __str__(self): + return f'{self.__class__.__name__}: bad idea is to divide by zero: {self._numerator}/{self._denominator}' + + +if __name__ == "__main__": + try: + while True: + try: + numerator = common.get_number_by_string(input("Input numerator >>>")) + denumerator = common.get_number_by_string(input("Input denumerator >>>")) + print(numerator/denumerator) + except ValueError: + continue + except ZeroDivisionError: + # ловим реальное деление на ноль и вызываем свой обработчик + raise MyZeroDivisionError(numerator, denumerator) + else: + break + except MyZeroDivisionError as mine_error: + print(mine_error) + # Корректно завершаемся + exit(1) diff --git a/lesson_8/hometask/task_3.py b/lesson_8/hometask/task_3.py new file mode 100644 index 0000000..93c3b1c --- /dev/null +++ b/lesson_8/hometask/task_3.py @@ -0,0 +1,73 @@ +# Создайте собственный класс-исключение, который должен +# проверять содержимое списка на наличие только чисел. +# Проверить работу исключения на реальном примере. +# Необходимо запрашивать у пользователя данные и +# заполнять список только числами. +# Класс-исключение должен контролировать типы данных элементов списка. +# +# **Примечание:**длина списка не фиксирована. +# Элементы запрашиваются бесконечно, пока пользователь +# сам не остановит работу скрипта, введя, например, команду “stop”. +# При этом скрипт завершается, сформированный список с числами выводится на экран. +# **Подсказка:**для данного задания примем, +# что пользователь может вводить только числа и строки. +# При вводе пользователем очередного элемента необходимо +# реализовать проверку типа элемента и вносить его в список, +# только если введено число. Класс-исключение должен не позволить +# пользователю ввести текст (не число) и отобразить соответствующее сообщение. +# При этом работа скрипта не должна завершаться. + +# класс-исключение сам проверяет содержимое списка на наличие только чисел? +# и вызывает себя тоже сам? +# я понял, что класс-исключение САМ ДОБАВЛЯЕТ ИЛИ НЕ ДОБАВЛЯЕТ элемент в список... + +from common import get_number_by_string + + +class NotNumberException(ValueError): + + def __init__(self, message: str, *args, **keyargs): + self.message = message + super().__init__(args, keyargs) + + # вообще, выглядит криво, это не функционал исключений. + # Лучше это выделить как отдельную функцию. + # Но раз так можно и есть намёки в задании, то ладно, + # тем более, урок по ООП) + # пусть всё делает метод класса, чтоб не смущать пользователя + @classmethod + def safe_append_to_list(cls, numstring_list: list, value): + """ + Проверка (не) числовых значений, (не) добавляемых в список + + :param numstring_list: список + :param value: значение (число или нет) + :return: None или вызов ошибки этого класса + """ + if not (isinstance(value, float) or isinstance(value, int)): + raise cls(f'element {value} of list is not a digit!') + else: + numstring_list.append(value) + + def __str__(self): + return self.message + + +if __name__ == "__main__": + num_list = list() + while True: + element = input("Input a digit (or try to input something else), please >>>") + if element == "stop": + print(num_list) + break + # попытка преобразования в число + try: + element = get_number_by_string(element) + except ValueError: + # ну строка так строка + pass + # собственно, задание + try: + NotNumberException.safe_append_to_list(num_list, element) + except NotNumberException as error: + print(error) diff --git a/lesson_8/hometask/task_4_5_6_equipment.py b/lesson_8/hometask/task_4_5_6_equipment.py new file mode 100644 index 0000000..5561381 --- /dev/null +++ b/lesson_8/hometask/task_4_5_6_equipment.py @@ -0,0 +1,321 @@ +# Начните работу над проектом «Склад оргтехники». +# Создайте класс, описывающий склад. А также класс «Оргтехника», +# который будет базовым для классов-наследников. +# Эти классы — конкретные типы оргтехники (принтер, сканер, ксерокс). +# В базовом классе определить параметры, общие для приведенных типов. +# В классах-наследниках реализовать параметры, уникальные для каждого типа оргтехники. + +from collections.abc import Iterable + + +class Office_Equipment: + # то нет смысла дополнять, только не изменять + _placement_types = ("Настольный", "Переносной", "Напольный") + # это можно дополнить, но безопасно... + _interface_types = {"USB", "DVI", "HDMI", "Bluetooth", "Wi-Fi"} + + # производитель + _manufacturer: str + # размещение - настольный, переносной, напольный + _placement: str + # тип устройства + _type: str + # название устройства + _name: str + + def __init__(self, manufacturer: str, name: str, eq_type: str, placement: str, interfaces: list): + # интерфейсы, разъёмы + # если объявить вне конструктора + # то один лист будет для всех объектов + # всех унаследованных классов + self._interfaces = [] + self._manufacturer = manufacturer + self._name = name + self._type = eq_type + self.placement = placement + self.interfaces = interfaces + + @classmethod + def get_placement_types(cls) -> tuple: + return cls._placement_types + + @classmethod + def get_interface_types(cls) -> list: + return cls._interface_types.copy() + + @classmethod + def add_interface_types(cls, value): + if isinstance(value, list): + cls._interface_types.update(set(value)) + elif isinstance(value, set): + cls._interface_types.update(value) + elif isinstance(value, str): + cls._interface_types.add(value) + else: + raise TypeError("Expected a string") + + @property + def placement(self): + return self._placement + + @placement.setter + def placement(self, value: str): + if value not in Office_Equipment.get_placement_types(): + message = f'{value} not in {self.__class__.__name__}.get_placement_types()' + raise ValueError(message) + self._placement = value + + @property + def interfaces(self): + return self._interfaces.copy() + + @interfaces.setter + def interfaces(self, value): + if isinstance(value, list) or isinstance(value, set): + if set(value).issubset(Office_Equipment.get_interface_types()): + self._interfaces.extend(value) + return + elif value in Office_Equipment.get_interface_types(): + self._interfaces.append(value) + return + raise ValueError(f"{value} not in {self.__class__.__name__}.get_interface_types()") + + @property + def manufacturer(self): + return self._manufacturer + + @property + def model_type(self): + return self._type + + @property + def name(self): + return self._name + + def __str__(self): + return f'{self._placement} {self.manufacturer} {self.name} {self._type}' + + def __repr__(self): + return f'{self._placement} {self.manufacturer} {self.name} {self._type}' + + +class Paper_Equipment(Office_Equipment): + # возможные форматы листа + # вообще, их куча + _available_formats = {"A0", "A1", "A2", "A3", "A4", "A5"} + + def __init__(self, manufacturer: str, name: str, eq_type: str, placement: str, + interfaces: list, formats: list): + # конкретный формат + self._formats = [] + self.paper_formats = formats + super().__init__(manufacturer, name, eq_type, placement, interfaces) + + @classmethod + def get_available_formats(cls): + return cls._available_formats.copy() + + @property + def paper_formats(self) -> list: + return self._formats.copy() + + @paper_formats.setter + def paper_formats(self, value): + if isinstance(value, list) or isinstance(value, set): + if set(value).issubset(Paper_Equipment.get_available_formats()): + self._formats.extend(value) + elif value in Paper_Equipment.get_available_formats(): + self._formats.append(value) + else: + raise ValueError(f"{value} not in {self.__class__.__name__}.get_available_formats()") + + +class Printer(Paper_Equipment): + # Возможные типы печати + _print_types = ('LED', "laser", "jet", "sublime", "thermo") + + # тип печати принтера + _print_type: str + # цветная или ч/б... + _color_print_schema: bool = False + # скорость печати + _print_speed: int + + def _specific_print_sets(self, print_type: str, color_schema: bool, print_speed: int): + if print_speed >= 0: + self._print_speed = print_speed + else: + raise ValueError("Print speed must be a positive!") + self.print_type = print_type + self._color_print_schema = color_schema + + # много аргументов - только именованные аргументы + def __init__(self, *, manufacturer: str, name: str, placement: str, interfaces: list, + formats: list, print_type: str, color_schema: bool, print_speed: int): + self._specific_print_sets(print_type, color_schema, print_speed) + super().__init__(manufacturer, name, 'Printer', placement, interfaces, formats) + + @classmethod + def get_print_types(cls): + return cls._print_types + + @property + def print_type(self): + return self._print_type + + # пока что сеттер задан только для удобства + # инициализации в __init__ + @print_type.setter + def print_type(self, value: str): + assert '_print_type' not in self.__dict__, "Print type already sets" + if value not in Printer.get_print_types(): + raise ValueError(f"{value} not in {self.__class__.__name__}.get_print_types()") + self._print_type = value + + @property + def color_print_schema(self) -> bool: + return self._color_print_schema + + @property + def print_speed(self): + return self._print_speed + + +class Scanner(Paper_Equipment): + # возможные типы сканеров + _scanner_types = ('3D', 'Tablet', 'Pull-through', 'Portable', 'Slide scanner', 'Photoscanner') + # возможные типы датчиков сканера + _sensor_types = ('CCS', 'CIS', 'CMOS') + # тип сканера + _scanner_type: str + # тип датчика + _sensor_type: str + # цветная или ч/б схема сканирования + _color_scan_schema: bool + # скорость сканирования + _scan_speed: int + + def _specific_scan_sets(self, scanner_type: str, sensor_type: str, color_schema: bool, + scan_speed: int): + if scan_speed >= 0: + self._scan_speed = scan_speed + else: + ValueError("Scan speed must be a positive!") + self.scanner_type = scanner_type + self.sensor_type = sensor_type + self._color_scan_schema = color_schema + + # много аргументов - только именованные аргументы + def __init__(self, *, manufacturer: str, name: str, placement: str, interfaces: list, + formats: list, scanner_type: str, sensor_type: str, color_schema: bool, + scan_speed: int): + self._specific_scan_sets(scanner_type, sensor_type, color_schema, scan_speed) + super().__init__(manufacturer, name, 'Scanner', placement, interfaces, formats) + + @classmethod + def get_scanner_types(cls): + return cls._scanner_types + + @classmethod + def get_sensor_types(cls): + return cls._sensor_types + + @property + def scanner_type(self): + return self._scanner_type + + # пока что сеттер задан только для удобства + # инициализации в __init__ + @scanner_type.setter + def scanner_type(self, value: str): + assert '_scanner_type' not in self.__dict__, "Print type already sets" + if value not in Scanner.get_scanner_types(): + raise ValueError(f"{value} not in {self.__class__.__name__}.get_scanner_types()") + self._scanner_type = value + + @property + def sensor_type(self): + return self._sensor_type + + # пока что сеттер задан только для удобства + # инициализации в __init__ + @sensor_type.setter + def sensor_type(self, value: str): + assert '_sensor_type' not in self.__dict__, "Color schema already sets" + if value not in Scanner.get_sensor_types(): + raise ValueError(f"{value} not in {self.__class__.__name__}.get_sensor_types()") + self._sensor_type = value + + @property + def scan_color_schema(self) -> bool: + return self._color_scan_schema + + @property + def scan_speed(self): + return self._scan_speed + + +class Xerox(Printer, Scanner): + """Многофункциональное устройство - возможность печати и сканирования""" + + # много аргументов - только именованные аргументы + def __init__(self, *, manufacturer: str, name: str, placement: str, interfaces: list, + formats: list, print_type: str, color_print_schema: bool, print_speed: int, + scanner_type: str, sensor_type: str, color_scan_schema: bool, + scan_speed: int + ): + self._specific_print_sets(print_type, color_print_schema, print_speed) + self._specific_scan_sets(scanner_type, sensor_type, color_scan_schema, scan_speed) + super(Scanner, self).__init__(manufacturer, name, 'PFE', placement, interfaces, formats) + # а вот так бы не получили конструктор из Paper_Equipment + # super(Printer, self).__init__(manufacturer, name, 'PFE', placement, interfaces, formats) + + +if __name__ == '__main__': + print(f'Интерфейсы {Office_Equipment.get_interface_types()}') + print(f'Типы принтера {Printer.get_print_types()}') + print(f'Форматы {Paper_Equipment.get_available_formats()}') + print(f'Расположение {Paper_Equipment.get_placement_types()}') + print(f'Типы сканера {Scanner.get_scanner_types()}') + print(f'Типы сенсора {Xerox.get_sensor_types()}') + try: + # Office_Equipment("Canon", "Canon ght900", "TechnoPencil", "Напотолочный", ["USB", "HDMI"]) + # Office_Equipment("Canon", "Canon ght900", "TechnoPencil", "Напольный", ["USB1", "HDMI"]) + # Printer(manufacturer="Xerox", name="Pbpfd", placement="Настольный", interfaces="USB", + # formats=['A0', 'A1'], print_type="Лапки", color_schema=False, print_speed=-100) + Scanner(manufacturer="HP", name="Ohho", placement="Переносной", interfaces=["USB", "HDMI"], + formats=['A0', 'A1'], scanner_type="Глаза", sensor_type="Вкусовые сосочки", + color_schema=True, scan_speed=10) + except ValueError as error: + print(error) + equipments = (Office_Equipment("Canon", "ght900", "TechnoPencil", "Напольный", ["USB", "HDMI"]), + Xerox(manufacturer="HP", name="Ohho", placement="Напольный", + interfaces=["USB", "USB", "HDMI", 'DVI', 'USB', 'Wi-Fi', 'Bluetooth'], formats=['A0', 'A1'], + print_type=Printer.get_print_types()[1], color_print_schema=True, + print_speed=10, scanner_type=Scanner.get_scanner_types()[0], + sensor_type=Scanner.get_sensor_types()[2], color_scan_schema=True, scan_speed=10), + Printer(manufacturer="Xerox", name="Pbpfd", placement="Настольный", interfaces="USB", + formats=['A0', 'A1'], print_type=Printer.get_print_types()[2], + color_schema=False, print_speed=100), + Scanner(manufacturer="HP", name="Ohho", placement="Переносной", interfaces=["USB", "HDMI"], + formats=['A0', 'A1'], scanner_type=Scanner.get_scanner_types()[1], + sensor_type=Scanner.get_sensor_types()[2], color_schema=False, scan_speed=10) + ) + + for equipm in equipments: + print(equipm.manufacturer) + print(equipm.name) + print(equipm.placement) + print(equipm.model_type) + print(equipm.interfaces) + if isinstance(equipm, Paper_Equipment): + print(equipm.paper_formats) + if isinstance(equipm, Printer): + print(equipm.print_speed) + print(equipm.print_type) + print(equipm.color_print_schema) + if isinstance(equipm, Scanner): + print(equipm.scanner_type) + print(equipm.sensor_type) + print(equipm.scan_color_schema) + print(equipm.scan_speed) diff --git a/lesson_8/hometask/task_4_5_6_store.py b/lesson_8/hometask/task_4_5_6_store.py new file mode 100644 index 0000000..e2da461 --- /dev/null +++ b/lesson_8/hometask/task_4_5_6_store.py @@ -0,0 +1,226 @@ +# Продолжить работу над первым заданием. +# Разработать методы, отвечающие за +# приём оргтехники на склад и передачу в +# определенное подразделение компании. +# Для хранения данных о наименовании и количестве +# единиц оргтехники, а также других данных, +# можно использовать любую подходящую структуру, +# например словарь. + +# Продолжить работу над вторым заданием. Реализуйте механизм валидации вводимых пользователем данных. +# Например, для указания количества принтеров, отправленных на склад, нельзя использовать строковый тип данных. + +# как будто всё в одном файле +from task_4_5_6_equipment import * + + +class NotIsInstance(ValueError): + def __init__(self, variable, variable_name: str, datatype: type, *args, **kvargs): + self._message = f'Некорректный тип данных {variable_name} ожидался' \ + f' {datatype.__name__}, получен {type(variable)}' + super().__init__(args, kvargs) + + def __str__(self): + return self._message + + +class Office_Equipment_Store: + _max_capacity: int + # словарь выглядит таким образом + # {производитель : {(название модели, тип): объекты}} + _store_equipments: dict + + def __init__(self, max_capacity): + assert max_capacity >= 0, "Объём склада не может быть отрицательным" + self._max_capacity = max_capacity + self._current_count = 0 + self._store_equipments = {} + + def _get_model_type_list(self, manufacturer: str, model: str, model_type: str) -> list: + manufacturers_dict = \ + self._store_equipments.setdefault(manufacturer, {}) + return manufacturers_dict.setdefault((model, model_type), []) + + @staticmethod + def __get_maker_model_type(office_equipment: Office_Equipment) -> tuple: + return office_equipment.manufacturer, office_equipment.name, office_equipment.model_type + + def _append_equipment(self, office_equipment: Office_Equipment): + """ + Добавление единицы оргтехники в + необходимые стуктуры хранения склада + + :param office_equipment: офисная техника + :return: None + """ + maker_name, model_name, model_type = \ + self.__get_maker_model_type(office_equipment) + models_type_list = self._get_model_type_list(maker_name, model_name, model_type) + models_type_list.append(office_equipment) + self._current_count += 1 + + @property + def common_count(self): + return self._current_count + + def append_equipment(self, office_equipment): + """ + Добавляем оргтехнику на склад + + :param office_equipment: единичная оргтехника или итерируемый объект + :return: None. Может быть выброшено ValueError! + """ + if self._current_count >= self._max_capacity: + raise ValueError("Store overloaded!") + # как правило, интересуют производитель и модель + # характеристики - это не про склад + if isinstance(office_equipment, Office_Equipment): + self._append_equipment(office_equipment) + elif isinstance(office_equipment, Iterable): + # Для итерируемых объектов исключений не будет + # Как будто мы пытаемся разгрузить партию, + # пришедшую на склад, пусть и не оттуда) + for unit in office_equipment: + if self._current_count >= self._max_capacity: + break + if not isinstance(unit, Office_Equipment): + continue + self._append_equipment(unit) + else: + message = f"That's not an {Office_Equipment.__name__} object" + raise ValueError(message) + + def get_equipment(self, manufacturer: str, name: str, count: int) -> list: + """ + Получить со склада технику по производителю и названию + + :param manufacturer: производитель оргтехники + :param name: название + :param count: количество оргтехники + :return: список из требуемой оргтехники. Или ошибки, если ничего нет. + """ + # куча проверок, прям как в 6 задании просили + if not isinstance(manufacturer, str): + raise NotIsInstance(manufacturer, 'manufacturer', str) + if not isinstance(name, str): + raise NotIsInstance(name, 'name', str) + if not isinstance(count, int): + raise NotIsInstance(count, 'count', int) + assert not count < 0, "Если Вы хотите пожертвовать оргтехнику, то это другой метод!" + assert count != 0, "Не стоит нас напрасно беспокоить!" + if manufacturer not in self._store_equipments.keys(): + raise ValueError("Такого производителя нет на складе!") + manufacturer_models_types = self._store_equipments.get(manufacturer) + if name not in {model for model, _ in manufacturer_models_types.keys()}: + raise ValueError("Такой модели нет на складе!") + # models_types = [(model, model_type) + # мне нужны ключи, причем не уникальные, + # а все, в количестве объектов данной модели + # данного производителя на складе + models_types_tuple = tuple(((model, model_type) + for (model, model_type), model_items in manufacturer_models_types.items() + for _ in model_items + if model == name)) + models_number = len(models_types_tuple) + if models_number < count: + # f-строки не всегда корректно выводятся непосредственно из исключения + message = f"Увы, на складе только {models_number} экземпляров!" + raise ValueError(message) + lost_models = [] + for cnt, model_type_pair in enumerate(models_types_tuple, start=0): + if cnt >= count: + break + models_list = manufacturer_models_types.get(model_type_pair) + lost_models.append(models_list.pop()) + if not bool(models_list): + # если список пуст, зачем нам словарь? + manufacturer_models_types.pop(model_type_pair) + if not bool(manufacturer_models_types): + # если словарь пуст, зачем нам этот словарь в словаре? + self._store_equipments.pop(manufacturer) + self._current_count -= 1 + + return lost_models + + def get_models(self, type_: str, manufacturer: str) -> set: + if not isinstance(manufacturer, str): + raise NotIsInstance(manufacturer, 'manufacturer', str) + if not isinstance(type_, str): + raise NotIsInstance(type_, 'name', str) + if manufacturer not in self._store_equipments.keys(): + raise ValueError("Такого производителя нет на складе!") + manufacturer_models_types = self._store_equipments.get(manufacturer) + if type_ not in (model_type for model, model_type in manufacturer_models_types.keys()): + raise ValueError("Нет такого типа оргтехники!") + return {model + for model, model_type in manufacturer_models_types.keys() + if model_type == type_} + + +if __name__ == "__main__": + # поле для экспериментов)) + # Названия для техники разных типов ожидаются уникальные + # Не будет принтер и сканер у одного производителя называться одинаково + # Но мы предусмотрели реакцию) + equipments = (Office_Equipment("Canon", "Canon ght900", "TechnoPencil", "Напольный", ["USB", "HDMI"]), + Xerox(manufacturer="HP", name="Ohho", placement="Напольный", + interfaces=["USB", "USB", "HDMI", 'DVI', 'USB', 'Wi-Fi', 'Bluetooth'], formats=['A0', 'A1'], + print_type=Printer.get_print_types()[1], color_print_schema=True, + print_speed=10, scanner_type=Scanner.get_scanner_types()[0], + sensor_type=Scanner.get_sensor_types()[2], color_scan_schema=True, scan_speed=10), + Printer(manufacturer="Xerox", name="Pbpfd", placement="Настольный", interfaces="USB", + formats=['A0', 'A1'], print_type=Printer.get_print_types()[2], + color_schema=False, print_speed=100), + Printer(manufacturer="Xerox", name="ghtad", placement="Настольный", interfaces="USB", + formats=['A0', 'A1'], print_type=Printer.get_print_types()[2], + color_schema=False, print_speed=100), + Printer(manufacturer="HP", name="Pbpfd", placement="Настольный", interfaces="USB", + formats=['A0', 'A1'], print_type=Printer.get_print_types()[2], + color_schema=False, print_speed=100), + Printer(manufacturer="HP", name="Pbpfd", placement="Настольный", interfaces="USB", + formats=['A0', 'A1'], print_type=Printer.get_print_types()[2], + color_schema=False, print_speed=100), + Scanner(manufacturer="HP", name="Ohho", placement="Переносной", interfaces=["USB", "HDMI"], + formats=['A0', 'A1'], scanner_type=Scanner.get_scanner_types()[1], + sensor_type=Scanner.get_sensor_types()[2], color_schema=False, scan_speed=10), + Scanner(manufacturer="HP", name="Ohho", placement="Переносной", interfaces=["USB", "HDMI"], + formats=['A0', 'A1'], scanner_type=Scanner.get_scanner_types()[1], + sensor_type=Scanner.get_sensor_types()[2], color_schema=False, scan_speed=10), + Scanner(manufacturer="HP", name="Ohhlo", placement="Переносной", interfaces=["USB", "HDMI"], + formats=['A0', 'A1'], scanner_type=Scanner.get_scanner_types()[1], + sensor_type=Scanner.get_sensor_types()[2], color_schema=False, scan_speed=11), + Scanner(manufacturer="Canon", name="Ohho", placement="Переносной", interfaces=["USB", "HDMI"], + formats=['A0', 'A1'], scanner_type=Scanner.get_scanner_types()[1], + sensor_type=Scanner.get_sensor_types()[2], color_schema=False, scan_speed=10) + ) + + current_store = Office_Equipment_Store(18) + current_store.append_equipment(equipments) + try: + for equipment in equipments: + current_store.append_equipment(equipment) + except ValueError as value_error: + print(value_error) + print(current_store.get_models("Scanner", "HP")) + print(current_store.get_models("Printer", "HP")) + try: + print(current_store.get_models("Printer", "Canon")) + except ValueError as value_error: + print(value_error) + print(f"Equipments count is {current_store.common_count}") + print(current_store.get_equipment("HP", "Ohho", 3)) + print(f"Equipments count is {current_store.common_count}") + print(current_store.get_equipment("HP", "Ohho", 2)) + print(f"Equipments count is {current_store.common_count}") + print(current_store.get_models("Scanner", "HP")) + + try: + print(current_store.get_models(5, "HP")) + # print(current_store.get_models("Scanner", 7)) + except NotIsInstance as error: + print(error) + try: + # print(current_store.get_equipment("HP", "Ohho", 0)) + print(current_store.get_equipment("HP", "Ohho", -1)) + except AssertionError as error: + print(error) diff --git a/lesson_8/hometask/task_7.py b/lesson_8/hometask/task_7.py new file mode 100644 index 0000000..4063fdb --- /dev/null +++ b/lesson_8/hometask/task_7.py @@ -0,0 +1,116 @@ +# Реализовать проект «Операции с комплексными числами». +# Создайте класс «Комплексное число», +# реализуйте перегрузку методов сложения и умножения +# комплексных чисел. Проверьте работу проекта, +# создав экземпляры класса (комплексные числа) и +# выполнив сложение и умножение созданных экземпляров. +# Проверьте корректность полученного результата. + +def my_abs(num): + if not (isinstance(num, int) or isinstance(num, float)): + raise TypeError("Expected a float or int datatypes for num") + return num if num >= 0 else -num + + +class Complex_Number: + + def __init__(self, real, imagine): + if not (isinstance(real, int) or isinstance(real, float)): + raise TypeError("Expected a float or int datatypes for real") + if not (isinstance(imagine, int) or isinstance(imagine, float)): + raise TypeError("Expected a float or int datatypes for imagine") + self._real = real + self._imagine = imagine + + def __add__(self, other): + """ + сложение комплексного числа с целым или десятичным или комплексным + целое или десятичное a можно представить как a + 0*i, где i == sqrt(-1) + + :param other: int или float или complex или Complex_Number + :return:Complex_Number + """ + if isinstance(other, Complex_Number): + # Пользоваться защищенными атрибутами вне класса некорректно. + # Но технически, мы внутри класса) Спасибо Python за свободу! + return Complex_Number(self._real + other._real, self._imagine + other._imagine) + if isinstance(other, complex): + return Complex_Number(self._real + other.real, self._imagine + other.imag) + if isinstance(other, int) or isinstance(other, float): + return Complex_Number(self._real + other, self._imagine) + raise TypeError("Expected a Complex_Number or float or int or complex datatypes") + + def __radd__(self, other): + if isinstance(other, complex): + return Complex_Number(self._real + other.real, self._imagine + other.imag) + if isinstance(other, int) or isinstance(other, float): + return Complex_Number(self._real + other, self._imagine) + raise TypeError("Expected a Complex_Number or float or int or complex datatypes") + + def __mul__(self, other): + """ + умножение комплексного числа + на целое или десятичное или комплексное + целое или десятичное a можно представить как a + 0*i, где i == sqrt(-1) + само умножение можно представить в общем виде как: + (a1+b1*i))*(a2+b2*i) == (a1*a2-b1*b2) + (a1b2 + a2b1)*i + так как i==sqrt(-1) + + :param other: int или float или complex или Complex_Number + :return: комплексное число Complex_Number - результат умножения + """ + if isinstance(other, Complex_Number): + new_real = self._real * other._real - self._imagine * other._imagine + new_imagine = (self._real * other._imagine + self._imagine * other._real) + return Complex_Number(new_real, new_imagine) + if isinstance(other, complex): + new_real = self._real * other.real - self._imagine * other.imag + new_imagine = (self._real * other.imag + self._imagine * other.real) + return Complex_Number(new_real, new_imagine) + if isinstance(other, int) or isinstance(other, float): + new_real = self._real * other + new_imagine = self._imagine * other + return Complex_Number(new_real, new_imagine) + raise TypeError("Expected a Complex_Number or float or int or complex datatypes") + + def __rmul__(self, other): + if isinstance(other, complex): + new_real = self._real * other.real - self._imagine * other.imag + new_imagine = (self._real * other.imag + self._imagine * other.real) + return Complex_Number(new_real, new_imagine) + if isinstance(other, int) or isinstance(other, float): + new_real = self._real * other + new_imagine = self._imagine * other + return Complex_Number(new_real, new_imagine) + raise TypeError("Expected a Complex_Number or float or int or complex datatypes") + + def __str__(self): + return f"{self._real}{'-' if self._imagine < 0 else '+'}{my_abs(self._imagine)}i" + + def __repr__(self): + self.__str__() + + +if __name__ == "__main__": + base_tuple = (5, -2) + reserve_tuple = (5, 2) + print(Complex_Number(*base_tuple)) + print(f"My radd {5 + Complex_Number(*base_tuple)}, trust radd {5 + complex(*base_tuple)}") + print(f"My add {Complex_Number(*base_tuple) + 5}, trust add {complex(*base_tuple) + 5}") + print( + f"My add {Complex_Number(*base_tuple) + complex(*reserve_tuple)}," + f"trust add {complex(*base_tuple) + complex(*reserve_tuple)}") + print( + f"My add {complex(*base_tuple) + Complex_Number(*reserve_tuple)}," + f"trust add {complex(*base_tuple) + complex(*reserve_tuple)}") + print( + f"My add {Complex_Number(*base_tuple) + Complex_Number(*reserve_tuple)}," + f"trust add {complex(*base_tuple) + complex(*reserve_tuple)}") + print(f"My mul {Complex_Number(*base_tuple) * 2}, trust mul {complex(*base_tuple) * 2}") + print(f"My rmul {2 * Complex_Number(*base_tuple)}, trust rmul {2 * complex(*base_tuple)}") + print(f"My rmul {complex(*base_tuple) * Complex_Number(*reserve_tuple)}," + f"trust mul {complex(*base_tuple) * complex(*reserve_tuple)}") + print(f"My mul {Complex_Number(*base_tuple) * complex(*reserve_tuple)}," + f"trust mul {complex(*base_tuple) * complex(*reserve_tuple)}") + print(f"My mul {Complex_Number(*base_tuple) * Complex_Number(*reserve_tuple)}," + f"trust mul {complex(*base_tuple) * complex(*reserve_tuple)}")