8.5. Самостоятельная работа¶
Примечание
При выполнении заданий используйте заготовки решений: -> Репозиторий.
Подробнее: см. Цикл выполнения и защиты заданий.
8.5.1. Комплексная задача¶
№8.5.1
Продолжите решение задачи № 7.5.1.
Используя результаты предыдущего решения, а также заготовку и Листинги 8.5.1-8.5.3, добавьте:
функцию загрузки данных из JSON-файла;
функцию сохранения результатов в CSV-файл;
обработку исключений.
Листинг 8.5.1 - JSON-файл
data.json с исходными данными¶ 1[
2 {
3 "name": "Иванов Иван",
4 "birthday": "01/12/2000",
5 "height": 170,
6 "weight": 70.5,
7 "car": true,
8 "languages": ["C++", "Python"]
9 },
10 {
11 "name": "Сергеев Сергей",
12 "birthday": "01/06/2001",
13 "height": 180,
14 "weight": 110.4,
15 "car": false,
16 "languages": ["Pascal", "Delphi"]
17 },
18 {
19 "name": "Николаева Мария",
20 "birthday": "14/07/1998",
21 "height": 180,
22 "weight": 66.9,
23 "car": true,
24 "languages": ["C#", "C++", "C"]
25 }
26]
Листинг 8.5.2 - Пример решения с файлами¶
1"""Комплексная задача.
2
3Сложность: O(N).
4"""
5
6import json
7import csv
8
9# Это пример кода, он может быть произвольно усложнен
10# в рамках ограничений темы
11#
12# Требования:
13#
14# - переделайте функцию load_db() на загрузку данных из JSON-файла;
15# - добавьте функцию save_db(), которая бы сохраняла db в CSV-файл;
16# - используйте функцию save_db() для сохранения результатов фильтрации;
17# - добавьте обработку исключений.
18
19
20# Замените атрибуты словаря и др. на соответствующие своему варианту
21
22def load_db(filename):
23 """Загрузить данные из json-файла 'filename'.
24
25 Функция не обрабатывает исключения.
26
27 Результат: list of dict или возбуждается исключение.
28
29 Сложность: O(1).
30 """
31 fh = None
32 try:
33 fh = open(filename, encoding="utf-8")
34 db = json.loads(fh.read())
35 finally:
36 if fh:
37 fh.close()
38
39 return db
40
41
42def save_db(db, filename):
43 """Сохранить данные 'db' в csv-файл 'filename'.
44
45 Функция не обрабатывает исключения.
46
47 Сложность: O(1).
48 """
49 with open(filename, "w", encoding="utf-8", newline="") as fh:
50 writer = csv.DictWriter(fh,
51 fieldnames=["name", "birthday", "height",
52 "weight", "car", "languages"],
53 quoting=csv.QUOTE_ALL)
54 writer.writeheader()
55 for item in db:
56 writer.writerow(item)
57
58
59def print_employee(item):
60 """Вывести объект 'item' на экран со всеми атрибутами.
61
62 Сложность: O(1).
63 """
64 print("Имя: {}".format(item["name"]))
65
66 ...
67
68
69def employees_filter(db, lang):
70 """Вернуть отфильтрованную базу 'db' (список сотрудников), у которых
71 в качестве языка программирования имеется 'lang'.
72
73 Аргументы:
74 - db (list of dict): база данных;
75 - lang (str): язык программирования.
76
77 Результат:
78 - (list of dict): отфильтрованная база данных.
79
80 Сложность: O(N).
81 """
82 # res - копия db, с сотрудниками, удовлетворяющими условию по языку
83 res = []
84 for item in db:
85 if lang in item["languages"]:
86 res.append(item)
87
88 return res
89
90
91def employee_employee_avg_height(db, younger_than):
92 """Вернуть средний рост среди сотрудников 'db', у которых
93 год рождения не менее 'younger_than'.
94
95 Аргументы:
96 - db (list of dict): база данных;
97 - younger_than (int): минимальный год рождения.
98
99 Результат:
100 - (float): если такие сотрудники есть;
101 (None): если таких сотрудников нет.
102
103 Исключения:
104 - ValueError: если кол-во найденных сотрудников равно 0.
105
106 Сложность: O(N).
107 """
108
109 r_sum = 0
110 r_col = 0
111 for item in db:
112 year = int(item["birthday"][-4:])
113 if year >= younger_than:
114 r_sum += item["height"]
115 r_col += 1
116
117 if r_col == 0:
118 raise ValueError
119
120 return r_sum / r_col
121
122
123try:
124 db = load_db("data.json")
125
126 while True:
127
128 print("\n-----")
129 print("Меню")
130 print("-----")
131 print("1. Список сотрудников.")
132 print("2. Фильтр по языку программирования.")
133 print("3. Средний рост сотрудников, моложе указанного г.р.")
134 print("\nВыберите пункт меню или нажмите ENTER для выхода: ", end="")
135
136 answer = input()
137
138 if answer == "1":
139 print("Содержимое базы данных ({}):".format(len(db)))
140 for i, item in enumerate(db, start=1):
141 print("{}.".format(i))
142 print_employee(item)
143
144 elif answer == "2":
145 lang = input("Введите язык программирования: ")
146 # "Нормализация" наименования языка на случай ошибки при вводе
147 lang = lang.capitalize()
148
149 res = employees_filter(db, lang)
150
151 if len(res) > 0:
152 print("Список сотрудников со знанием "
153 "языка программирования {} ({}):".format(lang, len(res)))
154 for i, item in enumerate(res, start=1):
155 print("{}.".format(i))
156 print_employee(item)
157
158 # Сохранение результата в файл
159 try:
160 save_db(res, "filter_result.csv")
161 print("Результат поиска сохранен в файл.")
162 except (IOError, csv.Error):
163 print("Не удалось сохранить результат поиска в файл.")
164 else:
165 print("Таких сотрудников нет.")
166
167 elif answer == "3":
168 try:
169 younger_than = int(input("Введите год рождения сотрудника: "))
170
171 res = employee_employee_avg_height(db, younger_than)
172
173 try:
174 print("Средний рост сотрудников, {} г.р. и моложе: "
175 "({:.1f}) см.".
176 format(younger_than, res))
177 except ValueError:
178 print("Таких сотрудников нет.")
179 except ValueError:
180 print("Год рождения должен быть целым числом.")
181
182 else:
183 break
184
185except (IOError, json.decoder.JSONDecodeError) as err:
186 print("Ошибка при чтении файла с данными:", err)
187
188except Exception as err:
189 print("Произошла ошибка!")
190 print("Тип:", type(err))
191 print("Описание:", err)
192
193
194# --------------
195# Пример вывода:
196#
197# -----
198# Меню
199# -----
200# 1. Список сотрудников.
201# 2. Фильтр по языку программирования.
202# 3. Средний рост сотрудников, моложе указанного г.р.
203#
204# Выберите пункт меню или нажмите ENTER для выхода: 1
205# Содержимое базы данных (3):
206# 1.
207# Имя: Иванов Иван
208# День рождения: 01/12/2000
209# Рост (см.): 170
210# Вес (кг.): 70.5
211# Есть машина: True
212# Языки программирования: ['С++', 'Python']
213# 2.
214# Имя: Сергеев Сергей
215# День рождения: 01/06/2001
216# Рост (см.): 180
217# Вес (кг.): 110.4
218# Есть машина: False
219# Языки программирования: ['Pascal', 'Delphi']
220# 3.
221# Имя: Николаева Мария
222# День рождения: 14/07/1998
223# Рост (см.): 180
224# Вес (кг.): 66.9
225# Есть машина: True
226# Языки программирования: ['C#', 'C++', 'C']
227#
228# -----
229# Меню
230# -----
231# 1. Список сотрудников.
232# 2. Фильтр по языку программирования.
233# 3. Средний рост сотрудников, моложе указанного г.р.
234#
235# Выберите пункт меню или нажмите ENTER для выхода: 2
236# Введите язык программирования: Python
237# Список сотрудников со знанием языка программирования Python (1):
238# 1.
239# Имя: Иванов Иван
240# День рождения: 01/12/2000
241# Рост (см.): 170
242# Вес (кг.): 70.5
243# Есть машина: True
244# Языки программирования: ['С++', 'Python']
245# Результат поиска сохранен в файл.
246#
247# -----
248# Меню
249# -----
250# 1. Список сотрудников.
251# 2. Фильтр по языку программирования.
252# 3. Средний рост сотрудников, моложе указанного г.р.
253#
254# Выберите пункт меню или нажмите ENTER для выхода: 3
255# Введите год рождения сотрудника: 2000
256# Средний рост сотрудников, 2000 г.р. и моложе: (175.0) см.
Листинг 8.5.3 - CSV-файл
filter_results.csv, сохранение результатов¶1"name","birthday","height","weight","car","languages"
2"Иванов Иван","01/12/2000","170","70.5","True","['C++', 'Python']"
3"Николаева Мария","14/07/1998","180","66.9","True","['C#', 'C++', 'C']"