Вы не можете улучшить то, что не можете измерить.

Некоторые люди хотят набрать вес, а другие хотят его сбросить. Я был в первой группе столько, сколько себя помню. Даже после того, как я изучал боевые искусства около 10 лет, мой вес резко не увеличился. Это сделало мое тело более здоровым, а разум - сильнее. Но все же этого было недостаточно, чтобы увеличить индекс массы тела. Я всегда был на нижней границе «здорового» диапазона ИМТ.

Для этого может быть много причин. Может быть, любовь к сладкому и закускам (быстрая энергия). Возможно, мой высокий метаболизм. Может быть, что-то еще. Или, скорее всего, все вместе. Кто знает, но факт остается фактом.

Оглядываясь на годы назад, единственное, что осталось, - это моя память о том, что у меня был некоторый дефицит веса, и нет данных, которые поддерживали бы или отслеживали изменения веса за эти годы.

Я часто говорю, что когда вы можете измерить то, о чем говорите, и выразить это числами, вы кое-что знаете об этом; но когда вы не можете измерить это, когда вы не можете выразить это в числах, ваши знания скудны и неудовлетворительны.
- Лорд Кельвин, 3 мая 1883 г.

В Data Science мы знаем, что наиболее трудоемкая часть анализа данных - это сбор и подготовка данных. Потому что без (хороших) данных нет анализа. Итак, у меня появилась идея поправить свой вес и улучшить некоторые навыки Python в будущем. Кроме того, это может быть интересный проект для сохранения рассудка, оставаясь дома из-за ужасной пандемии. Этот пост призван побудить людей использовать Python в повседневной жизни.

Начнем.

Идея

Мы хотим записывать данные наших измерений веса в определенный день (в идеале - каждый день). Мы снимаем измерение, затем записываем его в простой форме, чтобы сохранить в табличном / табличном формате (или что-то подобное). Другими словами, мы хотим, чтобы код генерировал для нас выходной файл и добавлял его содержимое с заданными входными данными. Так что в долгосрочной перспективе мы сделаем как можно меньше работы.

Давайте разберем процесс на цели - что нам нужно (и будем) изучать в этом посте шаг за шагом.

Цели

К концу этой статьи вы узнаете, как:

  1. взаимодействовать с кодом Python, используя аргументы командной строки sys.argv;
  2. проверьте, существует ли уже файл, используя OS модуль операционной системы;
  3. манипулировать файлами usingwith open();
  4. обрабатывать некоторые ошибки с помощью try-catch блока (бонус);
  5. добавить свою документацию (docstring) к любой функции (бонус);

Код

Мы хотим вызвать код с некоторыми дополнительными (командной строкой) аргументами для ввода измеренного веса. Самый простой способ - работать с необработанным кодом Python с расширением .py (вместо альтернативной интерактивной записной книжки).

Начнем с создания текстового документа с расширением .py, например, WeightTracker.py.

Давайте погрузимся!

Первым делом импортируем несколько библиотек

import numpy as np
import datetime
import os, sys

Получите сегодняшнюю дату и время. Удалите комментарий #, если вам нужно только значение даты (без времени)

currentDT = datetime.datetime.now()#.date()

Часть 1 (sys.argv)

Обычно, когда мы запускаем код Python из командной строки (терминала), он выглядит как python WeightTracker.py, если код называется «WeightTracker.py». По умолчанию имя кода присваивается нулевому системному аргументу sys.argv[0] - ноль, потому что в Python индексы начинаются с 0, а не с 1. В данном случае sys.argv[0] = WeightTracker.py. Чтобы проверить это, вы можете распечатать itprint(sys.argv[0]).

Если мы хотим предоставить список дополнительных аргументов, мы можем запустить код следующим образом python WeightTracker.py arg1 arg2 arg3 …. В простейшем случае мы хотим получить только наш собственный вес, например, использовать только один дополнительный аргумент. Таким образом, например, чтобы запустить наш код и записать вес 68,4 (единицы, например, кг), мы введем python WeightTracker.py 68.4 в терминале.

Мы читаем это значение и добавляем его в пустой массив. Затем мы определяем имя файла для сохранения даты и измерения веса.

daily_kg = sys.argv[1]
mass_array = []
mass_array.append(daily_kg)
filename = “My_weight_gain.txt”

Часть 2 (модуль ОС)

Модуль os позволяет нам использовать функции нашей операционной системы. Например, получение текущего рабочего каталога с помощью os.getcwd() или отображение списка файлов в каталоге с помощью os.listdir(<directory>) и т. Д.

Здесь мы заинтересованы в том, чтобы проверить, существует ли данный файл с os.path.isfile(<file>). Если это так (возможно, потому, что мы запускали этот код раньше), мы просто обновляем этот файл, используя сегодняшние значения. В противном случае нам нужно создать новый файл. Это простое if-else заявление

if os.path.isfile(filename):
   print("\n file exists \n appending with provided data ... ")
   # append an existing file
else: 
   print("\n file does not exists \n creating {}".format(filename))
   # create a new file

Часть 3 (создание файлов)

В Python мы можем писать (создавать) или читать файлы с помощью встроенной функции open. Короче говоря, он предоставляет файловый объект, который содержит методы и атрибуты для чтения, сохранения и управления файлами. Функция open принимает два параметра: имя файла (или путь + имя файла) и аргумент режима (чтение "r", запись "w" или добавление "a").

Примечание. всегда важно закрыть файл после открытия, потому что каждый открытый файл продолжает поглощать ресурсы.

Для нас способ обойти это выражение with. Он автоматически закрывает файл, даже если код обнаруживает ошибку. Код запускает все в блоке с отступом, а затем закрывает файловый объект.

Например, чтобы создать (записать) файл с именем «Hello.txt» и записать строку «Hello World!», Мы можем использовать оператор with следующим образом

with open('Hello.txt', 'w') as file:
    file.write("Hello World!")

Итак, вернемся к нашему коду. Мы модифицируем наш if-else оператор как

if os.path.isfile(filename):
   print("\n file exists \n appending with provided data ... ")
   with open(filename, "a") as file:
      file.write("{:>20} {:>20}\n".format(str(currentDT), daily_kg))
else:
   print("\n file does not exists \n creating {}".format(filename))
   with open(filename, "w") as file:
      file.write("{:>20} {:>20}\n".format("Time", "Mass (kg)"))
      file.write("{:>20} {:>10}\n".format(str(currentDT), daily_kg))

В принципе, на этом урок можно закончить, потому что наша программа работает. Он записывает сегодняшнюю дату и наши измерения веса.

Но мы еще не совсем довольны. Мы хотим иметь возможность обрабатывать возникающие исключения. Например, когда пользователь не указывает значение веса - мы хотим красиво выйти из программы и дать короткое четкое сообщение о том, что следует делать (часть 4). Также мы хотим дать пользователю несколько советов о том, как правильно запустить программу или просто описать программу в целом (часть 5).

Часть 4 (блок try-catch)

Тема создания и обработки исключений заслуживает отдельной статьи. Что такое исключения и почему мы должны о них заботиться?

Очень кратко и просто: исключения - это обнаруженные ошибки во время выполнения программы. Для их обработки обычно используют блок try-catch. Внутри блока try: мы запускаем код. В случае неудачи программа переходит в except: блок, где мы решаем, что делать дальше.

Давайте посмотрим, как это работает, вызвав простую функцию, которая делит одну переменную на другую. Мы намеренно разделим число на ноль, чтобы создать ошибку - и мы ее поймаем.

Вот функция. Мы определяем и называем это. Во втором случае делим на ноль.

def div(x, y):
    result = x / y
    return result
div(5,6) # result => 0.8333333333333334
div(5,0) # result => ZeroDivisionError: division by zero

Мы знаем, что операция деления на ноль не определена. Здесь мы легко можем увидеть, где произошла ошибка. Но что, если наша программа имеет десятки определений и разделена на разные файлы? Тогда может быть не так просто найти причину ошибки. Возможно, стоит подумать об этом заранее.

Кроме того, данный блок кода может выполнять некоторую дополнительную операцию, поэтому весь результат программы не сильно от него зависит. Затем, даже если данный блок выходит из строя и возвращает значение None (пустое) или значение NaN (не число), вся программа все равно будет выполняться.

В общем, хорошая идея - научиться обрабатывать исключения. В нашем примере с функцией div это может выглядеть так:

def div(x, y):
    try:
        result = x / y
    except:
        print('Division by zero is not allowed! Exiting ...')
        result = None
        
    return result

Вызов этой функции сейчас даст нам личное сообщение, в котором объясняется, что произошло, и возвращается объект theNone. Мы не получаем результата, но и наша программа не давит.

Это еще не все. Например, какие типы исключений существуют, как создавать и повторно вызывать исключения и т. Д. Эти вопросы выходят за рамки данной статьи. Если вы хотите узнать об этом больше, посетите мой краткий учебник по GitHub.

На мой взгляд, самая важная часть обработки исключений - всегда предоставлять некоторую информацию на месте и никогда не pass исключение. В противном случае невозможно будет отследить причину ошибки.

Возвращаясь к нашей программе, мы хотим учесть ее, поместив весь предыдущий код в блок try: indented. А внутри блока except: мы распечатаем название ошибки и короткую инструкцию о том, как правильно написать программу, например

try:
  
except Exception as e:
  # in case an Exception/Error arises, do the following:
  print("\nError: {}\n".format(e))
  
  messageFromDeveloper = "You need to provide the weight measurement as the first argument as following \npython <this code>.py <weight> \n for example \npython WeightTracker.py 75"
  print(messageFromDeveloper.ljust(40, '-'))

Если мы хотим получить общее представление о данной функции / методе, мы обычно используем help() метод. Давайте посмотрим, как мы можем вручную определить, что отображается при вызове функции справки.

Часть 5 (создание нашей документации)

В принципе, у каждого класса, модуля или функции должна быть строка документации (docstring). Строка документации описывает, что делает функция, и выглядит как комментарий в тройных одинарных или тройных двойных кавычках.

Опять же, здесь есть много информации, от точного формата строки до общих стилей документации. Здесь мы хотим увидеть, как создать простую строку документации для нашей функции. Даже если это может не соответствовать глобальному формату строк документации, вы можете сделать это следующим образом

"""
 This is a help doc
 
 To EXIT/QUIT interactive mode - press "q"
 
 This function is waiting for additional 
 command-line (terminal) argument upon call.
 
 python <this code>.py <weight>
 e.g., 
 python WeightTracker.py 75.0
 
 Otherwise an exception is thrown.
 ~~~
 Good luck and have a nice day!
 """

Чтобы увидеть это в действии, вы можете вызвать print(WeightTracker.__doc__) или help(WeightTracker). В последнем случае мы войдем в некую интерактивную оболочку, из которой мы сможем выйти, нажав «q».

Поздравляю! Теперь наша программа закончена. Мы с радостью можем записать наш вес для использования в будущем. Следующей частью будет чтение этого файла и анализ изменений веса. Например, с помощью визуализации и, возможно, даже предсказания нашего будущего веса с помощью машинного обучения.

Чтобы найти полный код этой программы, посетите мою страницу GitHub. Результирующий выходной файл .txt выглядит так:

Спасибо за внимание и дочитали до конца.

использованная литература

Есть ряд хороших ресурсов по Python, например,
docs.python.org
realpython.com

Контакт

Свяжитесь со мной в LinkedIn.

Загляните в мой GitHub.

P.S .: Если вам нравится непрерывное чтение на этой прекрасной платформе Medium.com, подумайте о поддержке авторов этого сообщества, подписавшись на членство ЗДЕСЬ. Это стоит всего 5 долларов в месяц и поддерживает всех авторов.