Skip to content

Instantly share code, notes, and snippets.

@baikov
Created June 6, 2022 14:28
Show Gist options
  • Save baikov/2ee7bc8d54054db4e8c76da177cc86b8 to your computer and use it in GitHub Desktop.
Save baikov/2ee7bc8d54054db4e8c76da177cc86b8 to your computer and use it in GitHub Desktop.
praktikum_reviewer_test_task
# 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