Автор: Шабанов Павел
E-mail: meteomail@yandex.ru
ABSTRACT
В основе языка python лежит идеология модульности. То есть программа на python - это набор взаимодействующих между собой модулей. В этой 3 части "Конструктора" поговорим о модулях, структуре программы и некоторых важных аспектах программирования кода на python
I. Структура программы. Главная программа
С точки зрения структурого программированиия любая программа состоит из главной программы и подпрограмм (как внешних, так и внутренних). Это верно и для python, где всегда можно выделить главную программу Главная программа - это тот файл с расширением "py", где следующая конструкция выдаст значение "main" (нижние подчеркивания важны):
if(__name__ == "__main__"):
print 'It is a main programm module-file'
else:
print 'It is just a module'
It is a main programm module-file
Здесь системная конструкция "name" определяет является ли данный модуль главным, то есть главной программой, или нет. В python модуль и программа, по сути, синонимы. Все программы - модули. Другое дело, что модуль-программа может вызывать код, выраженный в виде функций, других модулей-программ. Делается это с помощью команды import:
import math
print 'PI number is %.10f' % math.pi # formatted output
PI number is 3.1415926536
Python позволяет вызывать модули в усеченном виде: с помощью псевдонимов и с помощью вызова конкретных функций из модуля. В первом случае можно заменить длинное имя модуля, которое необходимо будет указывать при вызове функций этого модуля, на более короткое:
import math # without using short name
print math.pi
import math as m # using short name
print m.pi
3.14159265359 3.14159265359
Во втором случае можно вызвать только одну функцию из модуля, так нужна только она, а остальной код импортируемого модуля не нужен для работы данной программы. Такой вызов позволяет осушествить конструкция "from ... import". Эту конструкцию можно объединить с использованием сокращенного имени (для числа пи не актуально, но для функций - спасительно):
import math # without using short name
print math.pi
from math import pi, cos # using from
print pi
print 'cos: %f' % cos(0.0) # formatted output
from math import pi as pin # using from & as
print pin
3.14159265359 3.14159265359 cos 1.000000 3.14159265359
Также можно импортировать все содержимое модуля так, чтобы не указывать имя модуля перед вызовом функции из импортиуемого модуля.
from math import *
print sin(1.0)
print pi
0.841470984808 3.14159265359
Стоит отметить, что модуль загружается один раз, при первом вхождении в главную программу. Для перезагрузки модуля нужно использовать функцию reload(). Нужно помнить, что импортированные с помощью from функции и идентификаторы не будут перезагружены, как и скомпилированные модули, написанные на других языках, например на fortran90.
II. Пользовательские модули
Поняв, что такое модули, как их подключать и как вызывать, перейдём к созданию пользовательских модулей. Основная идея создания пользовательских модулей - систематизация пользовательских и сторонних функций. Это очень необходимо при работе с большими проектами и разнообразными задачами.
Создать модуль очень просто - создаём новый файл "scimod" с расширением "py", сохраняем там необходимые функции и - вуаля - всё готово! Здесь это трудно показать, но это очень просто. Положим, файл "scimod.py" выглядит примерно так:
from scipy import stats
def trend(x,y,out='spv'):
'''
From given vectors 'x' and 'y' linear trend components are calculated \n
**INPUT:** \n
`x [np.ma.arr]` - numpy 1D array of values \n
`y [np.ma.arr]` - numpy masked 1D array of values \n
`char [str]` - defines the calculated parameter (sum, mean \
and so on)(default='mean') \n
`anom [bool]` - switch array values into anomalies divided on std \
(default=False) \n
**OUTPUT:** \n
`slope [float]` - slope koef. \n
`p_value [float]` - p_value \n
`sig [float]` - shows alpha-level, where trend is \
statistically significant \n
Author: Pavel Shabanov \n
Email: meteomail@yandex.ru \n
Blog: http://geofortran.blogspot.ru \n
'''
slope, intercept, r_value, p_value, std_err = stats.mstats.linregress(x,y)
ss = np.arange(1.0,0.00,-0.01)
for i in ss:
# print p_value, i
if (p_value < i):
sig = i
if (out == 'all'):
return slope, intercept, r_value, p_value, std_err
elif (out == 'ab'):
return slope, intercept
elif (out == 'spv'):
return slope, p_value
elif (out == 'pv'):
return p_value
elif (out == 's'):
return slope
elif (out == 'spvr'):
return slope, p_value, r_value**2
else:
return slope, p_value, sig
Этот модуль с именем по умолчанию scimod содержит функцию trend, которая в свою очередь опирается на модуль scipy, а точнее не функцию linregress. Полный путь к функции linregress из модуля scipy выглядит так:
import scipy.stats.mstats.linregress as linetr
Чтобы вызвать пользовательский модуль и его функции, нужно в новой программе с расширением ".py", например "main.py", написать:
import numpy as np
import scimod as sm
x1 = np.arange(10)
y1 = np.random.random(10)
print x1,y1
a,b = sm.trend(x1,y1,out='ab')
print 'A: %f | B: %f' % (a,b)
--------------------------------------------------------------------------- ImportError Traceback (most recent call last) <ipython-input-23-5528a48df56f> in <module>() 1 import numpy as np 2 ----> 3 import scimod as sm 4 5 x1 = np.arange(10) ImportError: No module named scimod
Увы, модуля (то есть файла) с таким названием нет в здешнем окружении. Во второй части Конструктора я писал, где python ищет модули. В этом интерпретатору помогают переменная среды PYTHONPATH и функция sys.path модуля sys. Отсюда вывод, что не из любого места можно вызывать модуль в другой модуль, а только из мест, в которых python ищет модули. Имеет смысл добавить в переменную среды PYTHONPATH путь к папке, где будут лежать пользовательские модули. Тогда они не будут путаться под ногами в рабочих папках и будут доступны для работы с любого места на компьютере.
III. Как писать понятный код на python
В Python есть официальный документ, который регламентирует как надо писать код. Он называется PEP8 и идеалогически восходит к основам дзен-питона, то есть постулатов, которых нужно придерживаться при программировании и разработке. Русский перевод PEP8 можно почитать здесь: http://pythonworld.ru/osnovy/pep-8-rukovodstvo-po-napisaniyu-koda-na-python.html
Про правила импортирования модулей там написано, в том числе, следующее:
Импорты всегда помещаются в начале файла, сразу после комментариев к модулю и строк документации, и перед объявлением констант.
Импорты должны быть сгруппированы в следующем порядке:
Таким образом, импорт пользовательских модулей должен быть в начале файла, после импорта модулей из стандартных (math, dateime и др.) и сторонних (numpy, matplotlib и др.) библиотек.
Авторский опыт подсказыает, что пользовательские функции нужно сортировать по модулям согласно назначению. То есть функции-преобразователи данных в одну кучу, а функции-рисовалки - в другую. Приведу для примера кусочек содержания пользовательского модуля с говорящим названием "brash.py":
import matplotlib.pyplot as plt
import numpy as np
def graph2d(x, y, color='black',legend=False):
'''
Это функция рисует двумерный график по двум входящим массивам.
**INPUT:**
`x [np.array] - argument, time`
`y [np.array] - function`
`color [str] - graph color (Default: 'black')`
`legend [bool] - print or not graph legend (Default: False)`
**OUTPUT:**
`picture` - 2D graph
'''
xy = plt.plot(x,y,color,label='Random')
# xy2 = plt.plot(x,y-0.5,color)
plt.grid(True)
plt.ylabel('Y')
plt.xlabel('Time')
plt.xlim(x[0],x[-1])
if(legend):
plt.legend(frameon=False, loc='best')
plt.show()
# ----- PROGRAM BODY -----
# Testing our module
N = 10
x1 = np.arange(N)
y1 = np.random.random(N)
pic = graph2d(x1,y1, color='red',legend=True)
print 'Описание функции graph2d:', graph2d.__doc__
Описание функции graph2d: Это функция рисует двумерный график по двум входящим массивам. **INPUT:** `x [np.array] - argument, time` `y [np.array] - function` `color [str] - graph color (Default: 'black')` `legend [bool] - print or not graph legend (Default: False)` **OUTPUT:** `picture` - 2D graph
Не забываем писать строки комментариев! =) И да, в функции нет return, то есть функция возвращает None. В случае картинок, когда нужно визуально оценить результат, это нормально. Также можно делать и в случае, когда необходимо сохранить рисунок в виде файла.
IV. Заключение
Программировать свои модули в python - это легко и просто! А главное, что это очень удобно! Нужно лишь начать использовать их и очень скоро ваша работа станет более легкой, код - читаемым, а состояние дел - упорядоченным. Лёгкой работы!