test1/fitness_tracker.py

154 lines
4.6 KiB
Python

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
}