Полное решение
# sales_report.py
import os
import sys
from collections import defaultdict
def read_sales_data(file_path):
"""Считывает данные из .txt файла и возвращает список записей."""
sales = []
with open(file_path, "r", encoding="utf-8") as file:
for line in file:
parts = line.strip().split(",")
# Пропускаем строки с неправильным количеством полей
if len(parts) != 5:
continue
name, date, amount, category, city = parts
year, month, day = date.split("-")
sales.append({
"name": name,
"date": date,
"amount": int(amount),
"category": category,
"city": city,
"year": year,
"month": month,
"day": day,
})
return sales
def write_category_reports(output_dir, grouped_sales):
"""Создаёт файлы с отчётами по категориям в формате 'дата,продавец,сумма'."""
for (year, month, category), records in grouped_sales.items():
# Формируем путь к файлу категории
category_file = os.path.join(output_dir, year, month, f"{category}.txt")
# Создаём все промежуточные папки, если их ещё нет
os.makedirs(os.path.dirname(category_file), exist_ok=True)
# Сортируем записи по дате
sorted_records = sorted(records, key=lambda x: x["date"])
with open(category_file, "w", encoding="utf-8") as file:
for record in sorted_records:
file.write(f"{record['date']},{record['name']},{record['amount']}\n")
def write_monthly_reports(output_dir, category_totals):
"""Создаёт общий отчёт по каждому месяцу с суммами продаж по категориям."""
for (year, month), category_sums in category_totals.items():
report_file = os.path.join(output_dir, year, month, "monthly_report.txt")
# Создаём папки перед записью файла
os.makedirs(os.path.dirname(report_file), exist_ok=True)
with open(report_file, "w", encoding="utf-8") as file:
# Записываем категории в алфавитном порядке
for category, total in sorted(category_sums.items()):
file.write(f"{category},{total}\n")
# Общая сумма по месяцу
file.write(f"Full,{sum(category_sums.values())}\n")
def process_sales_data(file_path, output_dir):
"""Обрабатывает продажи и создаёт отчёты по категориям и общие отчёты по месяцам."""
sales = read_sales_data(file_path)
# grouped_sales хранит записи по (year, month, category)
grouped_sales = defaultdict(list)
# category_totals хранит суммы по категориям внутри (year, month)
category_totals = defaultdict(lambda: defaultdict(int))
for record in sales:
key = (record["year"], record["month"], record["category"])
grouped_sales[key].append(record)
category_totals[(record["year"], record["month"])][record["category"]] += record["amount"]
write_category_reports(output_dir, grouped_sales)
write_monthly_reports(output_dir, category_totals)
# --- Точка входа ---
if len(sys.argv) < 3:
print("Usage: python sales_report.py <input_file> <output_directory>")
sys.exit(1)
input_file = sys.argv[1]
output_directory = sys.argv[2]
process_sales_data(input_file, output_directory)
print("Reports generated successfully!")
Пошаговое объяснение
1. Чтение данных
Функция read_sales_data открывает файл в кодировке utf-8 и читает его построчно. Каждая строка разбивается по запятой. Если полей не пять, строка пропускается — это защита от пустых или повреждённых строк.
Из даты извлекаются год, месяц и день, чтобы потом группировать записи по периодам.
2. Группировка
Две структуры данных:
grouped_sales— словарь, где ключ(year, month, category), а значение — список записей.category_totals— словарь, где ключ(year, month), а значение — ещё один словарьcategory → total_amount.
Обе структуры используют defaultdict, поэтому не нужно проверять наличие ключа перед добавлением.
3. Запись файлов по категориям
Функция write_category_reports проходит по группам, сортирует записи по дате и записывает их в файл. Путь собирается через os.path.join, а папки создаются через os.makedirs(..., exist_ok=True).
4. Запись месячных отчётов
Функция write_monthly_reports записывает суммы по категориям в алфавитном порядке и добавляет строку Full с общей суммой всех категорий.
5. Обработка аргументов
В блоке if __name__ == "__main__": (в решении используется прямая проверка в глобальной области) проверяется, что пользователь передал два аргумента. Если нет — программа выводит подсказку и завершается с кодом 1.
Как проверить
- Создайте файл
sales_data.txtс тестовыми данными из раздела Задания. - Сохраните решение в файл
sales_report.py. - Запустите:
python sales_report.py sales_data.txt reports. - Откройте папку
reports/и проверьте структуру и содержимое файлов.