Created
June 6, 2022 14:28
-
-
Save baikov/2ee7bc8d54054db4e8c76da177cc86b8 to your computer and use it in GitHub Desktop.
praktikum_reviewer_test_task
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# TIP: общие советы по коду: | |
# - Использовать аннотацию типов | |
# (см. PEP 484 - https://peps.python.org/pep-0484/) | |
# - Добавить описания классов и методов | |
# (см. PEP 257 – Docstring Conventions https://peps.python.org/pep-0257/) | |
# - отсутствует консистентность (одинаковые методы решения одинаковых проблем) | |
# Примеры ниже по коду | |
# TIP: для улучшения восприятия кода можно импортировать конкретный класс | |
# библиотеки, который планируем использовать | |
# EXAMPLE: | |
# from datetime import datetime as dt | |
import datetime as dt | |
# WARN: отсутствует документирование класса | |
class Record: | |
# EXAMPLE: пример docstring | |
# """Класс записей для класса Calculator и его потомков | |
# """ | |
# TIP: вынести формат даты в отдельную переменную класса (проще изменить | |
# и использовать) | |
# EXAMPLE: | |
# DATE_FORMAT = "%d.%m.%Y" | |
# WARN: отсутствует docstring и аннотация типов метода | |
# TIP: Инициализировать переменную date значением None для упрощения | |
# дальнейшей проверки | |
# EXAMPLE: | |
# def __init__(self, amount: float, comment: str, date: str = None) -> None: | |
def __init__(self, amount, comment, date=''): | |
# EXAMPLE: пример docstring для инициализатора | |
# """Инициализатор класса Record | |
# | |
# Args: | |
# amount (float): денежная сумма или количество килокалорий | |
# comment (str): комментарий, поясняющий, на что потрачены деньги | |
# или откуда взялись калории. | |
# date (str, optional): дата создания записи. Значение по | |
# умолчанию — текущая дата. | |
# """ | |
self.amount = amount | |
# WARN: код неудобен для чтения и понимания, отформатирован не по PEP8 | |
# EXAMPLE: пример с учетом предыдущих правок может выглядеть так | |
# if date is not None: | |
# self.date = dt.strptime(date, self.DATE_FORMAT).date() | |
# else: | |
# self.date = dt.now().date() | |
# TIP: инициализацию даты можно вынести в отдельный метод, подробнее - | |
# https://www.geeksforgeeks.org/getter-and-setter-in-python/ | |
self.date = ( | |
dt.datetime.now().date() if | |
not | |
date else dt.datetime.strptime(date, '%d.%m.%Y').date()) | |
# TIP: переменные лучше инициализировать в той же последовательности, | |
# в которой они передаются | |
self.comment = comment | |
# WARN: отсутствует документирование класса | |
class Calculator: | |
# WARN: отсутствует docstring и аннотация типов метода | |
def __init__(self, limit): | |
self.limit = limit | |
# TIP: Если переменная предназначена для внутреннего использования, | |
# можно показать это при помощи одинарного нижнего подчеркивания перед | |
# ее именем (используется на уровне договоренности, | |
# подробнее - https://pep8.org/#descriptive-naming-styles) | |
# TIP: можно указать тип переменной | |
# self._records: list[Record] = [] | |
self.records = [] | |
# WARN: отсутствует docstring и аннотация типов метода | |
def add_record(self, record): | |
# WARN: лучше указать тип переменной и организовать проверку, т.к. | |
# в дальнейшем происходит обращение к полям экземпляра класса Record | |
self.records.append(record) | |
# WARN: отсутствует docstring метода | |
def get_today_stats(self): | |
today_stats = 0 | |
# WARN: грубое игнорирование PEP. 1) Record уже используется для имени | |
# класса. 2) Переменные именуются с маленькой буквы | |
for Record in self.records: | |
# TIP: лучше определить переменную today до цикла, как это сделан | |
# в методе get_week_stats | |
if Record.date == dt.datetime.now().date(): | |
# TIP: Более "питоновский" вариант | |
# today_stats += record.amount | |
today_stats = today_stats + Record.amount | |
# ERROR: в задании просят округлять до сотых | |
# EXAMPLE: | |
# return "%.2f" % today_stats | |
return today_stats | |
# WARN: отсутствует docstring метода | |
def get_week_stats(self): | |
week_stats = 0 | |
today = dt.datetime.now().date() | |
for record in self.records: | |
# TIP: нужно упростить выражение | |
# EXAMPLE: | |
# if 0 <= (today - record.date).days < 7: | |
if ( | |
(today - record.date).days < 7 and | |
(today - record.date).days >= 0 | |
): | |
week_stats += record.amount | |
return week_stats | |
# WARN: отсутствует документирование класса | |
class CaloriesCalculator(Calculator): | |
# WARN: отсутствует docstring и аннотация типов метода | |
# TIP: вот как раз то, что написано в комментарии принято | |
# писать в docstring | |
def get_calories_remained(self): # Получает остаток калорий на сегодня | |
# TIP: вычисление остатка лучше вынести в отдельный метод базового | |
# класса (DRY - https://ru.wikipedia.org/wiki/Don’t_repeat_yourself) | |
# WARN: переменным нужно давать осмысленные имена, об этом говорит и | |
# PEP, и требования к заданию. Например: calories_balance | |
x = self.limit - self.get_today_stats() | |
if x > 0: | |
# ERROR: в требованиях к коду написано - "Бэкслеши для переносов | |
# не применяются" | |
# ERROR: нужно вернуть результат с точностью до сотых | |
# TIP: лучший способ вернуть длинную строку это подразумеваемое | |
# продолжение строки внутри скобок (подробнее - | |
# https://peps.python.org/pep-0008/) | |
# EXAMPLE: | |
# return ( | |
# 'Сегодня можно съесть что-нибудь ещё, но с общей ' | |
# f'калорийностью не более {x:.2f} кКал' | |
# ) | |
return f'Сегодня можно съесть что-нибудь' \ | |
f' ещё, но с общей калорийностью не более {x} кКал' | |
# TIP: else и скобки не нужны, если мы попали в if, то return уже | |
# произошел | |
else: | |
return('Хватит есть!') | |
# WARN: отсутствует документирование класса | |
class CashCalculator(Calculator): | |
USD_RATE = float(60) # Курс доллар США. | |
EURO_RATE = float(70) # Курс Евро. | |
# WARN: отсутствует docstring и аннотация типов метода | |
# ERROR: в условии написано, что метод принимает только строку кода валюты | |
# USD_RATE и EURO_RATE переменные класса, они и так находятся в области | |
# видимости меода, не нужно их передавать | |
# подробнее - (https://habr.com/ru/company/otus/blog/487952/) | |
def get_today_cash_remained(self, currency, | |
USD_RATE=USD_RATE, EURO_RATE=EURO_RATE): | |
# WARN: лишняя переменная | |
currency_type = currency | |
# TIP: такой действие уже было, удобнее определить метод в | |
# базовом классе | |
cash_remained = self.limit - self.get_today_stats() | |
# TIP: Этот участок кода можно упростить используя словарь с валютами, | |
# что позволит расширить функционал и избавиться от кучи if | |
# EXAMPLE: определим переменную класса | |
# CURRENCY_TYPE = { | |
# 'usd': {'rate': USD_RATE, 'name': 'USD', 'symbol': '$'}, | |
# 'eur': {'rate': EURO_RATE, 'name': 'Euro', 'symbol': '€'}, | |
# 'rub': {'rate': 1, 'name': 'Рубли', 'symbol': '₽'} | |
# } | |
# cash_remained /= self.CURRENCY_TYPE[currency]['rate'] | |
if currency == 'usd': | |
cash_remained /= USD_RATE | |
currency_type = 'USD' | |
elif currency_type == 'eur': | |
cash_remained /= EURO_RATE | |
currency_type = 'Euro' | |
elif currency_type == 'rub': | |
# ERROR: по логике тут cash_remained /= 1.00 | |
cash_remained == 1.00 | |
currency_type = 'руб' | |
# WARN: блоки кода следует отделять пустой строкой | |
if cash_remained > 0: | |
# WARN: в рекомендациях к коду "В f-строках применяется только | |
# подстановка переменных" | |
# EXAMPLE: | |
# return ( | |
# f'На сегодня осталось {cash_remained:.2f}' | |
# f' {self.CURRENCY_TYPE[currency]['symbol']}' | |
# ) | |
return ( | |
f'На сегодня осталось {round(cash_remained, 2)} ' | |
f'{currency_type}' | |
) | |
# WARN: в рекомендациях к коду "использовать Guard Block" | |
elif cash_remained == 0: | |
return 'Денег нет, держись' | |
elif cash_remained < 0: | |
# ERROR: в требованиях к коду написано - "Бэкслеши для переносов | |
# не применяются", рекомендации были выше по коду | |
# WARN: лишняя пустая строка | |
return 'Денег нет, держись:' \ | |
' твой долг - {0:.2f} {1}'.format(-cash_remained, | |
currency_type) | |
# ERROR: а где расширенный функционал методов get_today_stats | |
# и get_week_stats? Судя по заданию предполагается вывод статистики в | |
# определенной валюте | |
# TODO: дописать методы get_today_stats и get_week_stats | |
def get_week_stats(self): | |
super().get_week_stats() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment