реализованы все функции и основной сценарий

This commit is contained in:
Артём Садаков 2026-04-16 20:33:55 +03:00
commit 3bf10a7461
3 changed files with 338 additions and 0 deletions

9
data/workouts.json Normal file
View File

@ -0,0 +1,9 @@
[
{
"date": "2026-04-28",
"type": "swimming",
"duration_min": 1200,
"distance_km": 2.0,
"calories": 120
}
]

154
fitness_tracker.py Normal file
View File

@ -0,0 +1,154 @@
import json
import os
from typing import Optional
def load_workouts(file_path: str) -> list:
try:
with open(file_path, 'r', encoding='utf-8') as file:
workouts = json.load(file)
return workouts if isinstance(workouts, list) else []
except (FileNotFoundError, json.JSONDecodeError, IOError):
return []
def filter_by_type(workouts: list, workout_type: str) -> list:
return [w for w in workouts if w.get('type') == workout_type]
def filter_by_date_range(workouts: list, start_date: str, end_date: str) -> list:
return [w for w in workouts if start_date <= w.get('date', '') <= end_date]
def total_calories(workouts: list) -> int:
return sum(w.get('calories', 0) for w in workouts)
def average_duration(workouts: list) -> float:
if not workouts:
return 0.0
total_duration = sum(w.get('duration_min', 0) for w in workouts)
return total_duration / len(workouts)
def best_distance(workouts: list) -> Optional[dict]:
distance_workouts = [w for w in workouts if w.get('distance_km', 0) > 0]
if not distance_workouts:
return None
best = max(distance_workouts, key=lambda x: x.get('distance_km', 0))
return {
'date': best.get('date'),
'type': best.get('type'),
'distance_km': best.get('distance_km')
}
def calories_per_minute(workout: dict) -> float:
duration = workout.get('duration_min', 0)
calories = workout.get('calories', 0)
if duration == 0:
return 0.0
return calories / duration
def add_workout(workouts: list, date: str, workout_type: str, duration_min: int,
distance_km: float, calories: int, avg_heart_rate: int = None) -> list:
valid_types = ['running', 'swimming', 'cycling', 'strength']
if workout_type not in valid_types:
raise ValueError(f"Неверный тип тренировки. Допустимые: {valid_types}")
if duration_min <= 0:
raise ValueError("Длительность должна быть больше 0")
if calories <= 0:
raise ValueError("Калории должны быть больше 0")
if distance_km < 0:
raise ValueError("Дистанция не может быть отрицательной")
workout = {
'date': date,
'type': workout_type,
'duration_min': duration_min,
'distance_km': distance_km,
'calories': calories
}
if avg_heart_rate is not None:
workout['avg_heart_rate'] = avg_heart_rate
workouts.append(workout)
return workouts
def get_heart_rate_zones(workouts: list) -> dict:
zones = {
'low': 0,
'moderate': 0,
'high': 0
}
for workout in workouts:
heart_rate = workout.get('avg_heart_rate')
if heart_rate is not None:
if heart_rate < 120:
zones['low'] += 1
elif heart_rate <= 150:
zones['moderate'] += 1
else:
zones['high'] += 1
return zones
def generate_monthly_report(workouts: list, year: int, month: int) -> dict:
month_workouts = []
for w in workouts:
date = w.get('date', '')
if date and date.startswith(f"{year}-{month:02d}"):
month_workouts.append(w)
if not month_workouts:
return {
'total_workouts': 0,
'total_calories': 0,
'total_distance_km': 0.0,
'avg_duration_min': 0.0,
'workouts_by_type': {},
'most_frequent_type': ''
}
total_workouts = len(month_workouts)
total_calories = sum(w.get('calories', 0) for w in month_workouts)
distance_types = ['running', 'swimming', 'cycling']
total_distance = sum(w.get('distance_km', 0) for w in month_workouts
if w.get('type') in distance_types)
avg_duration = sum(w.get('duration_min', 0) for w in month_workouts) / total_workouts
workouts_by_type = {}
for w in month_workouts:
w_type = w.get('type')
workouts_by_type[w_type] = workouts_by_type.get(w_type, 0) + 1
if workouts_by_type:
max_count = max(workouts_by_type.values())
most_frequent = [t for t, c in workouts_by_type.items() if c == max_count]
most_frequent_type = sorted(most_frequent)[0]
else:
most_frequent_type = ''
return {
'total_workouts': total_workouts,
'total_calories': total_calories,
'total_distance_km': round(total_distance, 2),
'avg_duration_min': round(avg_duration, 1),
'workouts_by_type': workouts_by_type,
'most_frequent_type': most_frequent_type
}

175
main.py Normal file
View File

@ -0,0 +1,175 @@
from fitness_tracker import *
import os
def save_workouts(file_path: str, workouts: list) -> None:
try:
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(workouts, file, indent=2, ensure_ascii=False)
print(f"\nДанные сохранены в {file_path}")
except IOError as e:
print(f"\nОшибка при сохранении: {e}")
def main():
print("=" * 60)
print("ФИТНЕС ТРЕКЕР - АНАЛИЗ ТРЕНИРОВОК")
print("=" * 60)
FILE_PATH = "data/workouts.json"
workouts = load_workouts(FILE_PATH)
print(f"\nЗагружено {len(workouts)} тренировок")
print("\n" + "=" * 60)
print("ОБЩАЯ СТАТИСТИКА")
print("=" * 60)
print(f"\nВсего тренировок: {len(workouts)}")
total_cals = total_calories(workouts)
print(f"Всего калорий: {total_cals}")
avg_dur = average_duration(workouts)
print(f"Средняя длительность: {avg_dur:.1f} минут")
best = best_distance(workouts)
if best:
print(f"Лучшая дистанция: {best['distance_km']} км ({best['type']}, {best['date']})")
else:
print("Лучшая дистанция: нет тренировок с дистанцией")
print("\n" + "=" * 60)
print("ФИЛЬТРАЦИЯ ПО ТИПУ ТРЕНИРОВКИ")
print("=" * 60)
valid_types = ['running', 'swimming', 'cycling', 'strength']
while True:
workout_type = input("\nВведите тип тренировки (running/swimming/cycling/strength): ").lower()
if workout_type in valid_types:
break
print(f"Неверный тип. Допустимые: {valid_types}")
filtered = filter_by_type(workouts, workout_type)
print(f"\nТренировок типа '{workout_type}': {len(filtered)}")
print("\n" + "=" * 60)
print("МЕСЯЧНЫЙ ОТЧЁТ")
print("=" * 60)
while True:
try:
year = int(input("\nВведите год (например, 2024): "))
month = int(input("Введите месяц (1-12): "))
if 1 <= month <= 12:
break
print("Месяц должен быть от 1 до 12")
except ValueError:
print("Введите целое число")
report = generate_monthly_report(workouts, year, month)
print(f"\nОТЧЁТ ЗА {year}-{month:02d}")
print("-" * 40)
print(f"Всего тренировок: {report['total_workouts']}")
print(f"Всего калорий: {report['total_calories']}")
print(f"Общая дистанция: {report['total_distance_km']} км")
print(f"Средняя длительность: {report['avg_duration_min']} мин")
print("\nРаспределение по типам:")
for w_type, count in report['workouts_by_type'].items():
print(f" {w_type}: {count}")
print(f"\nСамый частый тип: {report['most_frequent_type'] if report['most_frequent_type'] else 'нет данных'}")
month_workouts = [w for w in workouts if w.get('date', '').startswith(f"{year}-{month:02d}")]
hr_zones = get_heart_rate_zones(month_workouts)
print("\nПУЛЬСОВЫЕ ЗОНЫ (за месяц)")
print("-" * 40)
print(f"Низкая (< 120 bpm): {hr_zones['low']} тренировок")
print(f"Средняя (120-150 bpm): {hr_zones['moderate']} тренировок")
print(f"Высокая (> 150 bpm): {hr_zones['high']} тренировок")
print("\n" + "=" * 60)
print("ДОБАВЛЕНИЕ НОВОЙ ТРЕНИРОВКИ")
print("=" * 60)
add_new = input("\nДобавить новую тренировку? (да/нет): ").lower()
if add_new in ['да', 'yes', 'y', 'д']:
print("\nВведите данные новой тренировки:")
while True:
date = input("Дата (ГГГГ-ММ-ДД): ")
if len(date) == 10 and date[4] == '-' and date[7] == '-':
break
print("Неверный формат даты. Используйте ГГГГ-ММ-ДД")
while True:
w_type = input("Тип (running/swimming/cycling/strength): ").lower()
if w_type in valid_types:
break
print(f"Неверный тип. Допустимые: {valid_types}")
while True:
try:
duration = int(input("Длительность (минуты): "))
if duration > 0:
break
print("Длительность должна быть больше 0")
except ValueError:
print("Введите целое число")
while True:
try:
distance = float(input("Дистанция (км): "))
if distance >= 0:
break
print("Дистанция не может быть отрицательной")
except ValueError:
print("Введите число")
while True:
try:
calories = int(input("Калории: "))
if calories > 0:
break
print("Калории должны быть больше 0")
except ValueError:
print("Введите целое число")
hr_input = input("Средний пульс (опционально, Enter чтобы пропустить): ")
avg_heart_rate = int(hr_input) if hr_input.strip() else None
try:
workouts = add_workout(workouts, date, w_type, duration, distance, calories, avg_heart_rate)
print(f"\nТренировка успешно добавлена")
except ValueError as e:
print(f"\nОшибка: {e}")
save_workouts(FILE_PATH, workouts)
print("\n" + "=" * 60)
print("ДЕМОНСТРАЦИЯ ФУНКЦИИ calories_per_minute")
print("=" * 60)
if workouts:
first_workout = workouts[0]
intensity = calories_per_minute(first_workout)
print(f"\nПервая тренировка в списке:")
print(f"Дата: {first_workout.get('date')}")
print(f"Тип: {first_workout.get('type')}")
print(f"Длительность: {first_workout.get('duration_min')} мин")
print(f"Калории: {first_workout.get('calories')}")
print(f"\nИнтенсивность: {intensity:.2f} калорий в минуту")
else:
print("\nНет тренировок для демонстрации")
print("\n" + "=" * 60)
print("ПРОГРАММА ЗАВЕРШЕНА")
print("=" * 60)
if __name__ == "__main__":
main()