понедельник, 1 сентября 2014 г.

Исследовательский конструктор. Часть I. Основы

В детстве я очень любил играть в конструктор. Он был разный - деревянный и железный, пластмассовый и бумажный, с дырочками-верёвочками, "сделай сам" и с готовыми элементами. Мы растём и развиваемся, но типы деятельности универсальны. И если раньше я конструировал, мечтая покорить межзвёздное пространство, то сегодня я воплощаю в жизнь свои идеи, решая свои профессиональные задачи.
Этим постом я открываю серию, посвященную тому, как облегчить себе рабочие будни, программируя на Python. Для тех, кто занят или нетерпелив, я написал выжимку.

ABSTRACT

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




I. Цели и методы

Так как наша задача состоит в том, чтобы сделать работу более удобной и легкой, то нам придётся наводить порядок в коде. Мы должны (по идее так должно быть каждый раз, когда мы программируем) писать такой код, который:
а) легко читать (не только нам, но и коллеге Петру)
б) легко поддерживать/модифицировать
в) легко "заводить" программу-клон с нуля (отдохнувшие пару месяцев от программы люди меня поймут)
Основная парадигма состоит в разделении функционала по разным модулям и их использование в основной программе. При этом каждый модуль содержит набор типовых функций, которые нам необходимы в трудовой жизни. Получается, что программа собирается из функций, которые хранятся в модулях. Собственно мы будем делать почти тоже самое, что делает, скажем numpy. Такая схема позволяет быстро собрать главную программу из других программных единиц. Мне это очень напоминает конструктор, а вам?

II. Модуль. Инструкция import

Лучше, конечно, прочитать соответствующий раздел в учебнике (бумажный или электронный ресурс), многое тогда пойдёт легче или полетит элементарно. Итак, модуль - это такой же файл с расширением "py", что и основная программа, но структурно это не главная программа. Проверить является ли файл главной программой можно так:

if __name__ == '__main__':
    print 'It is the main program' # это главная программа
else:
    print 'It is a module' # 'это модуль

Вызвать модуль можно через import. Это инструкция позволяет нам соединять файлы или их кусочки в одну программу. В модуль мы будем помещать функции, которые далее станут атрибутами данного модуля. Атрибут "sum" модуля numpy мы вызываем, когда пишем:

xsum = np.sum(x, axis=1)

Создадим модуль mathik.py, который будет хранить три функции и иметь, соответственно три атрибута: функция нахождения максимума последовательности, минимума и суммы.

# -*- coding: utf-8 -*-

def minix(x):
    pass

def maxix(x):
    pass

def sumix(x):
    pass

Не сомневаюсь, что каждый читатель блога может заполнить "тела" функций кодом нахождения минимума, максимума и суммы последовательности. Тогда тело главной программы, согласно изложенной выше схеме, будет выглядеть примерно так:

# -*- coding: utf-8 -*-

import mathik as mk

t = [0,-1,4,8,15,-2,5,7,-6,0,10]

print 'MAX: %d' % (mk.maxix(t))
print 'MIN: %d' % (mk.minix(t))
print 'SUM: %d' % (mk.sumix(t))

III. Где хранятся модули? Пути поиска модуля

Идея понятна. Стоит отметить, что необходимые для импорта модули интерпретатор ищет либо в этой же папке, где лежит основная программа, либо в других местах (папках). Получить полный список путей, в которых выполняется поиск подключаемого модуля, позволяет модуль sys:

import sys
print sys.path # список путей к папкам, из которых модуль будет "виден"

Для поиска мест, откуда можно поймать модуль, в python есть специальная переменная среды - PYTHONPATH. Если вы поместите туда адрес каталога (папки) с созданными вами модулями, то можно спокойно их вызывать отовсюду. PYTHONPATH нужно искать в переменных среды вашей операционной системы. Для Linux - тут или на русском, а для Windows.
Иногда полезно добавить в список sys.path путь к модулю только на время работы программы. Для этого можно динамически добавлять в самой программе (естественно, до вызова необходимого модуля) строку к списку sys.path:

import sys
my_modulepath = 'C:/My_path/'
sys.path.append()
print sys.path

import my_module_which_is_in_my_modulepath

Когда закроется интерпретатор, забудется и добавленный путь.

IV. Импорт модуля в модуль. Горизонтальные связи модулей

Но что если нам этого мало и мы хотим график? Имеет смысл создать ещё один модуль "paint2D.py", где будут лежать подпрограммы для 2D рисования. Скажем, такой:

# -*- coding: utf-8 -*-

import mathik as mk # вызываем уже сделанный модуль. Будем использовать его атрибуты
import matplotlib.pyplot as plt

def graph(x):
    plt.plot(x,'g--')
    plt.plot(x.index(mk.maxix(x)),mk.maxix(x),'ro')
    plt.plot(x.index(mk.maxix(x)),mk.maxix(x),'bo')
    plt.text(5, 10, '%s' % str(mk.sumix(x)))
    plt.show()

В основной программе код будет такой:

# -*- coding: utf-8 -*-
import paint2D as p2d
x = [0,1,2,3,4,5,-6,6,7,8]
p2d.graph(x)

Если последовательность нам интересна как массив или временной ряд, то можно добавить в модуль "paint2D.py" функции для рисования гистограмм, ящиков с усами и спектрограмм.
Если нам понадобится отобразить информацию на карте, имеет смысл завести модуль "mymap.py" и т.д.

V. Преимущества предложенной методики

Через некоторое время у вас будет набор таких модулей, которые вам необходимы для работы. Чтобы собрать программу вам нужно будет подключить эти модули и воспользоваться необходимыми функциями. Это намного удобнее, чем писать небольшие программки или складировать в главную программу все подпрограммы (те, кто знают Фортран на windows, поймут меня). Главная программа получается краткая, нарядная, тестировать её проще (отключая и подсоединяя последовательно нужные модули-функции), будет меньше случайных ошибок, так как большую часть кода вы уже протестируете при сборке других программ. В общем, сплошной кайф, а не система!














Как перевести UV в направление и скорость ветра? How to convert wind UV-components to direction and velocity?

 Всё просто.  def uv2dir(u, v):     '''     Источник:     https://github.com/blaylockbk/Ute_WRF/blob/master/functions/wind_calc...