Как преобразовать csv в xls

import csv
from openpyxl import Workbook


def convert_csv_to_xlsx():
    wb = Workbook()
    sheet = wb.active

    CSV_SEPARATOR = ";"

    with open('G:/Мой диск/Рассвет/DC/PN_COUNT.CSV') as f:
        reader = csv.reader(f)
        for r, row in enumerate(reader):
            for c, col in enumerate(row):
                for idx, val in enumerate(col.split(CSV_SEPARATOR)):
                    cell = sheet.cell(row=r + 1, column=idx + 1)
                    cell.value = val.strip()
                    try:
                        cell.value = int(cell.value)
                    except ValueError:
                        pass

    wb.save('G:/Мой диск/Рассвет/DC/PN_COUNT.xlsx')


convert_csv_to_xlsx()

Код на Python. Умеет различать разделитель. Раскидывает данные по ячейкам, а не просто меняет расширение файла как некоторые примеры в интернете.

По ходу разработки выяснилось, что нужно удалить лишние пробелы, чтобы потом преобразовать строку в число.

Единственная проблема, которую не смог решить, это некорректное преобразование csv в xls, если в csv есть значения с запятой. Видимо проблема в используемой библиотеке openpyxl.

Настройка GitHub в PyCharm

  1. Заходим в File-Settings-Version Control-GitHub
  2. Кликаем Create API Token, вводим логин и пароль с GitHub’a
  3. Заходим VCS-Enable Version Control Systems. Если не всплывает ошибка, то переходим к п. 4, иначе см. примечание.
  4. Выбираем Git.
  5. Выбираем VCS-Import into Version Control-Share Project on GitHub.
  6. После этого всплывет окно, где нужно указать имя для папки, потом выбираете файлы для отправки и готово.

Но у меня возникли проблемы на этапе 3. Всплыла ошибка: Errors while executing git —version. exitCode=-1073741792 errors

После тырканий всплыла еще одна. PyCharm, что это??:

В общем если у вас что-то подобное, то нужно установить или переустановить программу Git. Скачиваем ее отсюда: https://git-scm.com/

Ставим. Везде, где был выбор, все оставил по умолчанию. И готово!

Возможно ваш PyCharm еще не тот путь видит на файл Git. Чтобы это исправить, заходим File-Settings-Version Control-Git и исправляем там путь. У меня это: C:\Program Files\Git\cmd\git.exe

======================================

Оффтоп вместо рекламы: Сарафан: поиск мастеров, если вдруг вам нужно вызвать мастера для решения бытовых вопросов

Запуск сторонних приложений

Работа с путями (os, os.path), проверка существования каталога перед созданием, запуск сторонней программы с аргументами:

#Есть программа (Image Magick для Windows), которая сжимает фотографии, и есть папка «Source» 
#с самими фотографиями. Каждую фотографию мы хотим уменьшить до 200px в ширину 
#(высота меняется пропорционально). Нужно для каждой фотографии запустить программу и результат 
#работы положить в папку «Result».

#Пример (ImageMagic): convert input.jpg -resize 200 output.jpg

#Задача №3. Дополнительная (не обязательная)
#Реализовать 4 параллельных процесса и разделить фотографии между ними.

import os
import subprocess

def all_list(): # полный список файлов
    source_dir = 'Source'    
    os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), source_dir))
    files_list = os.listdir(path=".")
    return files_list

def ensure_dir(file_path): # проверяем есть ли уже каталог с именем Result, если нет, то создаем
    if not os.path.exists(file_path):
        os.makedirs(file_path)

def main(files_list): 
    print('Идет обработка...')
    source_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Source')
    result_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Result')
    ensure_dir(result_dir)
    for i in files_list:
        input_path = os.path.join(source_dir, i)
        output_path = os.path.join(result_dir, i)
        command = 'convert ' + input_path + ' -resize 200 ' + output_path
        os.chdir(os.path.dirname(os.path.abspath(__file__)))
        subprocess.run(command) #subprocess.Popen('имя') - асинхронный запуск
    print('Готово')

main(all_list())

Формирование списка файлов, содержащих запрос

Очередная тренировка работы с кодировками, поиском слов. И немного про пути к файлам (os, os.path), есть пример использования исключений (try, except).

# Задание
# мне нужно отыскать файл среди десятков других
# я знаю некоторые части этого файла (на память или из другого источника)
# я ищу только среди .sql файлов
# 1. программа ожидает строку, которую будет искать (input())
# после того, как строка введена, программа ищет её во всех файлах
# выводит список найденных файлов построчно
# выводит количество найденных файлов
# 2. снова ожидает ввод
# поиск происходит только среди найденных на этапе 1
# 3. снова ожидает ввод
# ...
# Выход из программы программировать не нужно.
# Достаточно принудительно остановить, для этого можете нажать Ctrl + C

# Пример на настоящих данных

# python3 find_procedure.py
# Введите строку: INSERT
# ... большой список файлов ...
# Всего: 301
# Введите строку: APPLICATION_SETUP
# ... большой список файлов ...
# Всего: 26
# Введите строку: A400M
# ... большой список файлов ...
# Всего: 17
# Введите строку: 0.0
# Migrations/000_PSE_Application_setup.sql
# Migrations/100_1-32_PSE_Application_setup.sql
# Всего: 2
# Введите строку: 2.0
# Migrations/000_PSE_Application_setup.sql
# Всего: 1

# не забываем организовывать собственный код в функции

import os
import chardet

migrations = 'Migrations'
current_dir = os.path.dirname(os.path.abspath(__file__))

def all_list(): 
    'Формируем полный список файлов'
    migrations_dir = os.path.join(current_dir, migrations)
    file_list = os.listdir(path=migrations_dir)
    return file_list
    
def sql_list(all_list): 
    'Функция для отбора sql-файлов'
    sql_file_list = list() # пустой список sql-файлов
    for i in all_list:
        if i.endswith('.sql'):
            sql_file_list.append(i)
    return sql_file_list

def decode_files(file_name):
    'Раскодирует файл, возвращает содержимое в читаемом виде'
    with open(os.path.join(current_dir, migrations, file_name), 'rb') as f:
        data = f.read()
        result = chardet.detect(data)
        data = data.decode(result['encoding'])
        data = data.lower()
    return data
    
def search_string(sql_list):
    'Главная функция: ищет запрашиваемую строку в файлах, список при каждом запросе сужается'
    file_list = sql_list
    while True: 
        search = input('Введите строку (регистр не важен): ') 
        search = search.lower()
        containing_files = list() # пустой список файлов для формирования сужающегося списка
        for file_name in file_list: 
            if search in decode_files(file_name):
                containing_files.append(file_name)
                print(file_name)
        print('Всего: {}'.format(len(containing_files)))
        file_list = containing_files

if __name__ == '__main__':
    search_string(sql_list(all_list()))
            
    pass

 

Подсчет популярности слов в тексте

#Взять из github-репозитория все файлы с новостями в формате txt: newsfr.txt, newsit.txt, newsafr.txt, newscy.txt.
#Написать программу, которая будет выводить топ 10 самых часто встречающихся в новостях слов длиннее 6 символов для каждого файла.
#Не забываем про декомпозицию и организацию кода в функции. В решении домашнего задания вам могут помочь: split(), sort() или sorted().

# фукнция чтения файлов (ГОТОВО)
def read_files(name):
    import chardet
    with open(name, 'rb') as f:
        data = f.read()
        result = chardet.detect(data)
        original_text = data.decode(result['encoding'])
        return original_text

# функция подсчета слов длиннее 6 символов (ГОТОВО)
def count_word(original_text):
    to_list = original_text.split(' ')
    to_set = set()
    for i in to_list: # заполняем множество с уникальными словами длиной больше 6 символов
        if len(i) > 6:
            to_set.add(i)
    word_value = {} # ищем слова из множества в списке, считаем количество, формируем словарь типа слово:количество
    for i in to_set:
        count = 0
        for j in to_list:
            if i == j:
                count += 1
        word_value[i] = count
    return word_value # возвращаем словарь {слово:количество}

# функция сортировки и вывода ТОП-10 
def sort_top(word_value):
    register = list()
    l_dict = str(len(word_value))
    for i in word_value.items():
        l_word = str(i[1])
        register.append((len(l_dict)-len(l_word))*'0' + str(i[1]) + ' ' + i[0]) # разворачиваем и добавляем нули перед количеством для сортировка, делаем слияние элементов = '00012 слово'
    register.sort(reverse = True)
    top_10_list = list()
    top_10 = {}
    count = 1
    for j in register:
        top_10[count] = j.split(' ') # получаем словарь типа {1: (количество, слово)}          
        top_10[count][0] = int(top_10[count][0])   
        if count == 10:
            break
        count += 1
    return top_10 # возвращаем отсортированный словарь ТОП-10 {номер: (количеств, слово)}

# главная функция: запрашивает имя файла, запускает другие функции (ГОТОВО)
def main():
        while True:
            name = input('Введите имя файла: newsfr.txt, newsit.txt, newsafr.txt, newscy.txt. Выход - exit: ')
            if name == 'newsfr.txt' or name == 'newsit.txt' or name == 'newsafr.txt' or name == 'newscy.txt':
                print('Идет обработка файла ...')
                top_10 = sort_top(count_word(read_files(name)))
                for k in top_10.values():
                    print (k[0], ': ', k[1])
            elif name == 'exit':
                break
            else:
                print('Некорректный ввод, повторите.')
        
main()
  • сортировка через list.sort() — по умолчанию так, если нужна обратная сортировка, то list.sort(reverse=True), если по какому-то ключу, то list.sort(key=[ключ]). Если нужно, чтобы функция возвращала значение, то используем sorted вместо sort;
  • функция chardet для автоматического определения кодировки и перевода в UTF-8.

Аналог с JSON с доработками предыдущего кода (сортировка словаря по значениям через лямбда-функцию):

#Взять из github-репозитория все файлы с новостями в формате json: newsfr.json, newsit.json, newsafr.json, newscy.json.
#Написать программу, которая будет выводить топ 10 самых часто встречающихся в новостях слов длиннее 6 символов для каждого файла.
#Не забываем про декомпозицию и организацию кода в функции. В решении домашнего задания вам могут помочь: split(), sort() или sorted().

#{'rss': {'_version': '2.0',
#         '_xmlns:votpusk': 'https://www.votpusk.ru/news.asp',
#         'channel': {'category': 'ВгаШЧЬ - єШЯа',
#                     'description': 'єШЯа - »ХЭвР вгаШбвШзХбЪШе ЭЮТЮбвХЩ '
#                                    'ЯЮавРЫР І ѕВїГБє.АГ ',
#                     'items': [{'_id': '545166',
#                                'description': 'ІЫРбвШ єШЯаР аРббзШвлТРов '

def read_files(name):
    'Функция чтения файлов'
    import json
    import chardet

    with open(name, 'rb') as f:
        data = f.read()
        result = chardet.detect(data)
        data = data.decode(result['encoding'])
        data = json.loads(data) # внимание! load читает файл, loads читает строку
        original_text = ''
        for items in data['rss']['channel']['items']:
           original_text += ' ' + items['description']
        return original_text

def count_word(original_text):
    'функция подсчета слов длиннее 6 символов'
    to_list = original_text.split(' ')
    word_value = {}
    for word in to_list: 
        if len(word) > 6:
            if word in word_value:
                word_value[word] += 1
            else:
                word_value[word] = 1
    return word_value # возвращаем словарь {слово:количество}

def sort_top(word_value):
    'функция сортировки и вывода ТОП-10' 
    l = lambda word_value: word_value[1]
    sort_list = sorted(word_value.items(), key = l, reverse = True)
    count = 1
    top_10 = {}
    for word in sort_list:
        top_10[count] = word        
        count += 1        
        if count == 10:
            break
    return top_10

def main():
    'главная функция: запрашивает имя файла, запускает другие функции'
    while True:
        name = input('Введите имя файла: newsfr.json, newsit.json, newsafr.json, newscy.json. Выход - exit: ')
        if name == 'newsfr.json' or name == 'newsit.json' or name == 'newsafr.json' or name == 'newscy.json':
            print('Идет обработка файла ...')
            top_10 = sort_top(count_word(read_files(name)))
            for i in top_10.values():
                print (i[1], ': ', i[0])
        elif name == 'exit':
            break
        else:
            print('Некорректный ввод, повторите.')
        
main()

Запись в список из словарей в цикле

Столкнулся с проблемой при записи новых данных в список из словарей.

При прогоне цикла через обычное копирование получалось что-то такое:

[{Ингредиент: Молоко, Количество: 500, Ед: г}]
[{Ингредиент: Яйца, Количество: 500, Ед: г}, {Ингредиент: Яйца, Количество: 500, Ед: г}]
[{Ингредиент: Творог, Количество: 500, Ед: г}, {Ингредиент: Творог, Количество: 500, Ед: г}, {Ингредиент: Творог, Количество: 500, Ед: г}]
etc

Конструкция ingredient[‘measure’] = ingredient_info[2] оказалось, что меняет по всем списке ingredient_list, содержащем словари, значения по ключу ‘measure’.

Решить проблему удалось через полное копирование списка ingredient в список «а» через a = copy.deepcopy(ingredient). Функция находится в библиотеке copy, которую надо импортировать.

import copy

def cook_book_collector(file_path):
	cook_book = {}
	with open(file_path) as menu: 
		for line in menu: # проходимся по строкам
			dish = line.strip() # 1 строка = название блюда			
			ingredient = {}	# словарь для информации по ингредиенту	
			ingredient_list = [] # список ингредиентов
			for ing_number in range(1, int(menu.readline().strip())+1): # запускаем цикл от 1 до N ингредиентов
				ingredient_info = menu.readline().strip() # читаем строку, затем разбиваем ее на список, затем заполняем словарь ингредиентов
				ingredient_info = ingredient_info.split(' | ')
				
				ingredient['ingridient_name'] = ingredient_info[0]
				ingredient['quantity'] = ingredient_info[1]
				ingredient['measure'] = ingredient_info[2]
				a = copy.deepcopy(ingredient) # копируем словарь в новую переменную, чтобы на строках выше потом не переписались все данные
				ingredient_list.append(a) # добавляем в конец списка инфу по каждому новому ингредиенту
								
			cook_book[dish] = ingredient_list
			menu.readline()
		return cook_book

Как добавить Python в PATH

Решение для Windows 10:

  1. Открываешь месторасположение python
  2. Находишь там python.exe, кликаешь правой кнопкой мыши —> Свойства
  3. Копируешь ПОЛНОСТЬЮ все, что написано в поле «Расположение»
  4. Заходишь в Мой компьютер, правой кнопкой мыши по свободному полю —> Свойства
  5. В левой колонке выбираешь «Дополнительные параметры системы»
  6. Там находишь в самом низу кнопку «Переменные окружения»
  7. В открывшемся окне будет 2 области. В любой находишь переменную Path, кликаешь —> Создать —> вставляешь скопированный путь.
  8. Нажимаешь OK, OK, … пока все не закроется.

Проверяем. Запускаем Консоль, вводим python, запуститься должен Python.

командная строка

Работа с картотекой

p – people – команда, которая спросит номер документа и выведет имя человека, которому он принадлежит;
l – list – команда, которая выведет список всех документов в формате passport «2207 876234» «Василий Гупкин»;
s – shelf – команда, которая спросит номер документа и выведет номер полки, на которой он находится;
a – add – команда, которая добавит новый документ в каталог и в перечень полок, спросив его номер, тип, имя владельца и номер полки, на котором он будет храниться.

documents = [
        {"type": "passport", "number": "2207 876234", "name": "Василий Гупкин"},
        {"type": "invoice", "number": "11-2", "name": "Геннадий Покемонов"},
        {"type": "insurance", "number": "10006", "name": "Аристарх Павлов"}
      ]

directories = {
        '1': ['2207 876234', '11-2'],
        '2': ['10006'],
        '3': []
      }

def people(numbers):
  for doc_numbers in documents:
    if doc_numbers["number"] == numbers:
      print(doc_numbers["name"])
      break
  else:
    print('Такого номера документа нет в базе.')

def people_list():
  for persons in documents:
    print(persons['type'], '"'+persons['number']+'"', '"'+persons['name']+'"')
    
def shelf(numbers):
  break_marker = False
  for shelf_directories in directories.items():
    for doc_numbers in shelf_directories[1]:
      if doc_numbers == numbers:
        print('Данный документ должен лежать на полке', shelf_directories[0])
        break_marker = True
        break
    if break_marker == True:
      break
  else:
    print('Такого номера документа нет в базе.')
    
def add_command(params_type, number, name, directories_number):
  if int(directories_number) == 1 or int(directories_number) == 2 or int(directories_number) == 3:
    documents.append({"type": params_type, "number": number, "name": name})
    directories[directories_number].append(number)
  else:
    print('Введенной полки не существует. Запись не осуществлена.')
  
      
      
while True:
  command = input('\n \
  Введите одну из команд: p, l, s, a, d, m, as. \n \
  Для выхода наберите exit. \n \
  Для вызов справки наберите help. \n \
  Ваша команда: ')
  if command == 'p':
    people(input('\nВведите номер документа:'))
  elif command == 'l':
    people_list()
  elif command == 's':
    shelf(input('\nВведите номер документа:'))
  elif command == 'a':
    add_command(input('\nВведите тип документа:'), input('Введите номер документа:'), input('Введите имя:'), input('Введите номер полки (1, 2, 3):'))
  elif command == 'exit':
    break
  elif command == 'help':
    print('\n \
    p – people – команда, которая спросит номер документа и выведет имя человека, которому он принадлежит;\n \
    l – list – команда, которая выведет список всех документов в формате passport "2207 876234" "Василий Гупкин";\n \
    s – shelf – команда, которая спросит номер документа и выведет номер полки, на которой он находится;\n \
    a – add – команда, которая добавит новый документ в каталог и в перечень полок, спросив его номер, тип, имя владельца и номер полки, на котором он будет храниться.')
  else:
    print('Вы ввели некорректную команду, повторите ввод.')

 

Функции и условия: практика

Задание: сформировать базу данных и посчитать разные средние и лучшие показатели

students = {'ID01':
                {
                  'name': 'Сергей',
                  'surname': 'Серов',
                  'sex': 'мужской',
                  'experience': False,
                  'homeworks': {'1': 5, '2': 10, '3': 7, '4': 7, '5': 2},
                  'exam': 7
                },
            'ID02':
                {
                  'name': 'Сергей',
                  'surname': 'Иванилов',
                  'sex': 'мужской',
                  'experience': True,
                  'homeworks': {'1': 6, '2': 10, '3': 9, '4': 8, '5': 5},
                  'exam': 8
                },
            'ID03':
                {
                  'name': 'Мария',
                  'surname': 'Серова',
                  'sex': 'женский',
                  'experience': False,
                  'homeworks': {'1': 5, '2': 10, '3': 7, '4': 7, '5': 2},
                  'exam': 10
                },
           'ID04':
                {
                  'name': 'Виктория',
                  'surname': 'Цинберг',
                  'sex': 'женский',
                  'experience':True,
                  'homeworks': {'1': 8, '2': 10, '3': 7, '4': 6, '5': 8},
                  'exam': 7
                },
            'ID05':
                {
                  'name': 'Сергей',
                  'surname': 'Серов',
                  'sex': 'мужской',
                  'experience': False,
                  'homeworks': {'1': 8, '2': 10, '3': 8, '4': 8, '5': 8},
                  'exam': 10
                },
           'ID06':
                {
                  'name': 'Маргарита',
                  'surname': 'Арутунян',
                  'sex': 'женский',
                  'experience': True,
                  'homeworks': {'1': 8, '2': 10, '3': 8, '4': 8, '5': 8},
                  'exam': 10
                }
        }

#расчет средних оценок за домашки и экзамен
def ave_group(homework_or_exam, select_dictonary):      #функция принимает форму контроля и словарь (полный или отфильтрованный)
  sum_score = 0                                         #объявляем нулевую сумму баллов
  quantity = 0                                          #объявляем нулевой счетчик количества оценок
  if homework_or_exam == '1':                           # если пользователь ввел 1, то отрабатываем средние оценки за домашние задания
    for students_info in select_dictonary.values():     #погружаемся в информацию о студентах
      for score in students_info['homeworks'].values(): #погружаемся в словарь с оценками и берем оттуда только оценки
        sum_score += score                              #находим сумму оценок
        quantity += 1                                   #находим количество оценок
    average = sum_score/quantity 
    return average 
  elif homework_or_exam == '2':                         # если пользователь ввел 2, то отрабатываем средние оценки за экзамен
    for students_info in select_dictonary.values():     #погружаемся в информацию о студентах
      sum_score += students_info['exam']                #находим сумму оценок
      quantity += 1                                     #находим количество оценок
    average = sum_score/quantity 
    return average 
  else:
    print('Что-то пошло не так...')

#создаем новый словарь фильтруя по полу и опыту    
def dictonary_filter(sex, experience):                  #создаем новый словарь на основе отфильтрованных данных
                                                        # sex - допустимые значения: 0 - все, мужской, женский
                                                        # experience - допустимые значения: 0 - все, True - с опытом, False - без опыта
  new_dict_students = {}
  for id_number, new_dict_info in students.items():
    if (sex == 0 or new_dict_info['sex'] == sex) and (experience == 0 or new_dict_info['experience'] == experience):
      new_dict_students[id_number] = new_dict_info
  return new_dict_students

#поиск лучших      
def the_best():
  best_list = [] 
  max_score = 0
  for best_students in students.values():
    sum_score = 0                                       #начинаем расчет средней оценки за домашние задания
    quantity = 0
    for score in best_students['homeworks'].values(): 
        sum_score += score                              
        quantity += 1                                   
    average = sum_score/quantity 
    score = 0.6 * average + 0.4 * best_students['exam'] #считаем интегральную оценку
    if score > max_score:                               #если и.оценка > максимальной, то обновляем лист лучших  
      max_score = score
      best_list = [[best_students['name'], best_students['surname'], max_score]]
    elif score == max_score:                            #если и.оценка = максимальной, то добавляем в лист лучших  
      best_list.append([best_students['name'], best_students['surname'], max_score])
  if len(best_list) == 1:                               #если в списке лучших 1, то выводим одно сообщение
    print()
    print('Лучший студент: {} с интегральной оценкой {:.2f}'.format(best_list[0][0]+' '+best_list[0][1], max_score))
  elif len(best_list) > 1:                              #если в списке лучших >1, то формируем список из имен и фамилий и запускаем print
    name_surname_list = []
    for students_in_best_list in best_list:
      name_surname_list.append(students_in_best_list[0]+' '+students_in_best_list[1])
    print()
    print('Лучшие студенты: {} с интегральной оценкой {}'.format(', '.join(name_surname_list), max_score))
  else:
    print('Что-то пошло не так...')

#главная функция
def main():
  while True:
    command = input('\n\
    1 - вывести среднюю оценку за домашние задания и за экзамен по всем группе\n\
    2 - вывести среднеюю оценку за домашние задания и за экзамен по группе в разрезе пола и наличия опыта\n\
    3 - определить лучшего студента, у которого будет максимальный балл по формуле 0.6 * его средняя оценка за домашние задания + 0.4 * оценка за экзамен\n\
    exit - выход\n\
    Введите команду: ')
    if command == '1':
      print('')
      print('Средняя оценка за домашние задания по группе: {:.2f}'.format(ave_group('1', students)))
      print('Средняя оценка за экзамен по группе: {:.2f}'.format(ave_group('2', students)))
    elif command == '2':
      print('')
      print('Средняя оценка за домашние задания у мужчин: {:.2f}'.format(ave_group('1', dictonary_filter('мужской', 0))))
      print('Средняя оценка за экзамен у мужчин: {:.2f}'.format(ave_group('2', dictonary_filter('мужской', 0))))
      print('Средняя оценка за домашние задания у женщин: {:.2f}'.format(ave_group('1', dictonary_filter('женский', 0))))
      print('Средняя оценка за экзамен у женщин: {:.2f}'.format(ave_group('2', dictonary_filter('женский', 0))))
      print('Средняя оценка за домашние задания у студентов с опытом: {:.2f}'.format(ave_group('1', dictonary_filter(0, True))))
      print('Средняя оценка за экзамен у студентов с опытом: {:.2f}'.format(ave_group('2', dictonary_filter(0, True))))
      print('Средняя оценка за домашние задания у студентов без опыта: {:.2f}'.format(ave_group('1', dictonary_filter(0, False))))
      print('Средняя оценка за экзамен у студентов без опыта: {:.2f}'.format(ave_group('2', dictonary_filter(0, False))))
    elif command == '3':
      the_best()
    elif command == 'exit':
      break
    else:
      print()
      print('Вы ввели некорректную команду, повторите ввод.')
  
main()

Полезные заметки:

  • как избавиться от [ ] и опубликовать список через запятую: ‘, ‘.Join(list)
  • как опубликовать число с N знаками после запятой: {:.2f}.format(x)
  • работа со словарями dict.values() — достаем значений, dict.keys() — достаем ключи, dict.items() — достаем ключи и значения в виде кортежа: (ключ, значение)