if
, двоеточие и отступыРассмотрим следующий пример, являющийся ядром так называемого алгоритма блуждания, используемого во многих приложениях, например, в производство новых материалов и при изучения мозга. Действие заключается в случайном движении на север (N), юг (S), запад (W) или восток (E) с одинаковой вероятностью.
Нам нужно выбрать случайным образом одно из четырех чисел, чтобы задать направление движения. Таким образом, мы выбираем число, выполняем соответствующее движение, и повторяем этот процесс много раз. Итоговый путь является типичной реализацией диффузии молекулы.
Для реализации этого процесса мы сгенерируем случайное число из
интервала \( [0,1) \). Будем считать, что \( [0,0.25) \) соответствует N,
\( [0.25,0.5) \) --- E, \( [0.5,0.75) \) --- S и \( [0.75, 1) \)
--- W. Пусть x
, y
--- координаты точки на плоскости, a d
--- длина перемещения. Мы должны сначала проверить принадлежность
r
соответсвующему отрезку и выполнить действие. Когда ответ на
вопрос если положительный (true
), мы выполняем действие. Если ответ
отрицательный (false
), мы обрабатываем вопрос иначе если и
т.д. Последний тест может обрабатываться как иначе, так как уже
обработаны все варианты.
Код на Python для такой проверки выглядит следующим образом
# -*- coding: utf-8 -*-
import random
x = 0.0; y = 0.0; d = 0.1
r = random.random()
if 0 <= r < 0.25:
# перемещаемся на север
y = y + d
elif 0.25 <= r < 0.5:
# перемещаемся на восток
x = x + d
elif 0.5 <= r < 0.75:
# перемещаемся на юг
y = y - d
else:
# перемещаемся на запад
x = x - d
print x, y
Python предоставляет зарезервированные слова if
, elif
(сокращенно от else if) и else
. Эти инструкции работают по
следующим правилам:
if условие:
, elif
условие:
, else:
, здесь условие
--- булевское выражение
возвращающее значение True
или False
.условие
равно True
, следующий блок выражений с
отступами и остальные if
, elif
и else
пропускаются.условие
равно False
программа переходит к следующему
if
, elif
или else
.==
, !=
, <
,
<=
, >
и >=
.
Функции широко используются в программировании и являются одним из
основных понятий, которые необходимо освоить. В простейшем случае
понятие функция в программе очень близко к понятию математической
функции: некоторое входное число \( x \) преобразуется в некоторое
выходное число. Один из примеров функция \( \mathrm{arctg\,}x \),
которой в Python соответствует функция atan(x)
. Функции в Python
могут иметь ряд входных параметров и возвращать одно или несколько
значений или ничего не возвращать. Цель использования функций состоит
из двух частей:
Мы можем, например, модифицировать сценарий ball.py из раздела (Программа на Python с переменными), добавив функцию, как сделано в сценарии ball_func.py:
# -*- coding: utf-8 -*-
# Программа для вычисления положения мяча при вертикальном движении
# с использованием функции
def y(t):
v0 = 5 # Начальная скорость
g = 9.81 # Ускорение свободного падения
return v0*t - 0.5*g*t**2
t = 0.6 # Время
print y(t)
t = 0.9
print y(t)
При выполнении этого сценария Python интерпретирует код от строки с
ключевым словом def
до строки с ключевым словом return
(обратите внимание на двоеточие и отступы) как определение функции с
именем y
. Выражение, содержащее ключевое слово return
интерпретируется Python следующим образом: сначала выполняется
вычисление, затем возвращается его результат, в том месте где функция
будет вызвана. Функция зависит от t
, т.е. от одной переменной (мы
будем говорить, что функция принимает один аргумент или входной
параметр), значение которой должно быть задано при вызове функции.
Что на самом деле происходит, когда интерпретатором Python встречается
такой код? Строка с ключевым словом def
сообщает интерпретатору,
что здесь определяется функция с именем y
, которая имеет один
входной параметр t
.
Если функция содержит инструкции if-elif-else
, каждый из блока
может возвращать значение с помощью return
:
def check_sign(x):
if x > 0:
return u'x --- положительное число'
elif x < 0:
return u'x --- отрицательное число'
else:
return u'x равно нулю'
В этой ситуации только один блок будет выполнен при вызове функции
check_sign
.
У функции могут отсутствовать аргументы, или быть много аргументов, которые просто перечисляются в круглых скобках, и разделены запятыми. Проиллюстрируем это на примере. Модифицируем пример с подбрасыванием мяча следующим образом. Предположим, что мы бросаем мяч не вертикально вверх, а под углом. В этом случае требуется две координаты для описания позиции мяча в каждый момент времени. Согласно закону Ньютона (сопротивлением воздуха пренебрегаем) вертикальная координата описывается формулой \( y(t) = v_{0y}t - 0.5g t^2 \), а горизонтальная координата --- \( x(t) = v_{0x}t \). Теперь можно включить оба эти выражения в новую версию сценария, который выводит позицию мяча для заданного момента времени. Допустим, мы хотим вычислить эти значения для двух моментов времени \( t= 0.6 \) с и \( t = 0.9 \) с. Мы можем задать значения компонент начальной скорости \( v_{0x} \) и \( v_{0y} \). Сценарий может выглядеть следующим образом ball2d.py
def y(v0y, t):
g = 9.81
return v0y*t - 0.5*g*t**2
def x(v0x, t):
return v0x*t
initial_velocity_x = 2.0
initial_velocity_y = 5.0
time = 0.6
print x(initial_velocity_x, time), y(initial_velocity_x, time)
time = 0.9
print x(initial_velocity_x, time), y(initial_velocity_x, time)
В результате мы вычисляем и печатаем две координаты положения мяча для каждого из двух моментов времени. Отметим, что функции имеют два аргумента. Запуск сценария даст следующий вывод:
1.2 -0.5658
1.8 -2.17305
Функция может не иметь возвращаемого значения (в этом случае
инструкция return
опускается), а также возвращать более одного
значения. Например, две функции, которые мы только что определили,
можно заменить одной
def xy(v0x, v0y, t):
g = 9.81
return v0x*t, v0y*t - 0.5*g*t**2
При этом возвращаемые значения разделяются запятой. При вызове функции аргументы должны следовать в том же порядке, как и в определении. Теперь мы можем напечатать результат следующим образом:
print xy(initial_velocity_x, initial_velocity_y, time)
Два возвращаемых значения могут быть присвоены двум переменным, например, так
x, y = xy(initial_velocity_x, initial_velocity_y, time)
Теперь переменные x
и y
могут использоваться в коде.
Существует возможность варьировать число входных и выходных параметров
(используя *args
и **kwargs
конструкции для
аргументов). Однако, мы не будем рассматривать этот вариант.
Переменные, которые определены внутри функции (например, g
в
xy
), являются локальными переменными. Это означает, что они
видимы только внутри функции. Поэтому, если мы случайно попытаемся
использовать переменную g
вне функции, мы получим сообщение об
ошибке. Переменная time
определена вне функции и поэтому является
глобальной переменной. Она видима как вне, так и внутри
функции(ий). Если мы определим одну глобальную и одну локальную
переменные с одним и тем же именем, то внутри функции будет видима
только локальная переменная, при этом глобальная переменная не
изменяется при изменении локальной переменной с тем же именем.
Аргументы перечисленные в заголовке определения функции, как правило,
являются локальными переменными. Если нужно изменить значение
глобальной переменной внутри функции, следует определить переменную
внутри функции как глобальную, т.е., если глобальная переменная имеет
имя x
, то нам нужно написать global x
внутри определения
функции, прежде чем изменять её значение. После выполнения функции,
x
будет иметь измененное значение. Следует стараться определять
переменные там, где они необходимы.
Еще один полезный способ управления параметрами в Python заключается в использовании именованных аргументов. Этот подход позволяет задавать аргументам значения по умолчанию и дает больше свободы в вызове функций, так как порядок и количество аргументов может варьироваться.
Проиллюстрируем использование именованных аргументов на примере
функции, аналогичной xy
. Определим функцию xy_named
следующим
образом:
# -*- 4th Start
def xy_named(t, v0x = 0, v0y = 0):
g = 9.81
return v0x*t, v0y*t - 0.5*g*t**2
Здесь t
--- обычный или позиционный аргумент, тогда как v0x
и v0y
--- именованные аргументы. В общем случае, может быть
несколько позиционных и несколько именованных аргументов, но
позиционные аргументы всегда должны следовать перед именованными в
определении функции. Именованные аргументы имеют значение по
умолчанию, в нашем примере vx0
и v0y
по умолчанию равны
нулю. В сценарии функция xy_named
может быть вызвана разными
способами. Например,
print xy_named(0.6)
выполнит вычисления с t = 0.6
и значениями,заданными по умолчанию (в нашем
случае 0) для v0x
и v0y
. Два возвращаемых функцией
xy_named
значения будут выведены на экран. Если мы хотим
использовать другое значение для переменной v0y
, мы можем,
например, написать
print xy_named(0.6, v0y=4.0)
т.е. выполнить функцию xy_named
с t = 0.6
, v0x = 0
(значение по умолчанию) и v0y = 4.0
. В случае, когда есть
несколько позиционных аргументов, они должны следовать в том порядке,
в котором перечислены в определении функции, если мы не задаем явно
имя переменной в вызове функции. Используя явное задание имени
переменной в вызове функции, мы можем использовать любой порядок
аргументов функции. Например, мы можем вызвать функцию xy_named
следующим образом:
print xy_named(v0y=4.0, v0x = 1.0, t = 0.6)
При использовании любого языка программирования существует хорошая традиция включать небольшое пояснение о том, что делает функция, если это не очевидно. Такое пояснение называется строкой документации (doc string), которую в Python следует помещать в начале функции. Это пояснение предназначено для программистов, которые желают понять код, так что следует описать цель данного кода и, возможно, описать аргументы и возвращаемые значения. Например, мы можем написать
# -*- 5th Start
def xy_named(t, v0x = 0, v0y = 0):
"""Вычисляются координаты x и y положения мяча в момент времени t """
g = 9.81
return v0x*t, v0y*t - 0.5*g*t**2
Следует отметить, что функция может быть вызвана из других функций, а также входными параметрами функции могут быть не только числа. Любые объекты могут быть аргументами функции, например, строковые переменные или функции.
Функции прямо передаются как аргументы других функций, что проиллюстрировано в сценарии functions_as_args.py
# -*- coding: utf-8 -*-
def sum_xy(x, y):
return x + y
def prod_xy(x, y):
return x*y
def treat_xy(f, x, y):
return f(x,y)
x = 2; y = 3
print treat_xy(sum_xy, x, y)
print treat_xy(prod_xy, x, y)
При запуске этот сценарий сначала выведет на экран сумму x
и
y
, а затем произведение. Видно, что treat_xy
принимает имя
функции в качестве первого аргумента. Внутри treat_xy
это имя
используется для вызова соответствующей функции.
Функция также может быть определена внутри другой функции. В этом случае она становится локальной или вложенной функцией, видимой только функцией, внутри которой она определена. Функции определенные в главном сценарии называются глобальными функциями. Вложенная функция имеет полный доступ ко всем переменным родительской функции, т.е. функции, внутри которой она определена.
Короткие функции могут определяться компактно с помощью лямбда функций:
f = lambda x, y: x + 2*y
эквивалентно
def f(x, y):
return x + 2*y
Синтаксис состоит из ключевого слова lambda
и следующих за ним
набора аргументов, двоеточия и некоторого выражения, дающим в
результате объект, возвращаемый функцией. Лямбда функции особенно
удобно использовать в качестве аргументов функций:
print treat_xy(lambda x, y: x*y, x, y)
Вызов функций имеет недостаток, заключающийся в замедлении выполнения программы. Как правило, разбиение программы на функции считается хорошим тоном, но в частях, содержащий очень интенсивные вычисления, например, внутри длинных циклов, нужно находить баланс между удобством вызова функции и вычислительной эффективностью, избегающей вызовы функций. Можно предложить правило, когда разрабатывается программа, содержащая много функций, а затем на стадии оптимизации, когда все вычисления корректны, удалять вызовы функций, которые замедляют выполнение кода.
Ниже приведен небольшой пример в оболочке IPython, где вычисляется процессорное время при выполнение вычислений с массивами при использовании и без использования вспомогательной функции
In [1]: import numpy as np
In [2]: a = np.zeros(1000000)
In [3]: def add(a, b):
...: return a+b
...:
In [4]: %timeit for i in range (len(a)): a[i] = add(i, i+1)
10 loops, best of 3: 150 ms per loop
In [5]: %timeit for i in range (len(a)): a[i] = i + i+1
10 loops, best of 3: 93.2 ms per loop
Многие вычисления являются повторяющимися и, естественно, языки программирования имеют некоторые циклические конструкции. В этом разделе мы рассмотрим такие конструкции языка Python.
for
Начнем с инструкции for
. Предположим, мы хотим вычислить квадраты
чисел от 3 до 7. Это можно сделать с помощью следующей инструкции:
for i in [3, 4, 5, 6, 7]:
print i**2
Обратите внимание на двоеточие и отступ!
Что происходит, когда интерпретатор Python обрабатывает данный код? Во
первых ключевое слово for
сообщает интерпретатору, что будет
выполняться цикл. Python затем придерживается правил, определенных для
таких конструкций, и понимает, что (в представленном примере) цикл
должен быть выполнен 5 раз (т.е., следует выполнить 5 итераций), при
этом переменная i
принимает последовательно значения 3, 4, 5, 6,
7
. Во время каждой итерации выполняется выражение внутри цикла
(т.е. print i**2
). После каждой итерации, значение i
автоматически изменяется. При достижении последнего значения,
выполняется последняя итерация и цикл завершается. При выполнении
сценарий выведет последовательно 9, 16, 25, 36
и
49
. Переменная i
часто называется счетчик цикла, а выбор
имени этой переменной (здесь i
) остается за программистом.
Отметим, что внутри цикла может быть несколько выражений, которые
будут выполнятся с одним и тем же значением i
.
В языке Python целые значения, определяемые для счетчика цикла, часто
получаются с помощью встроенной функции range
. Функция range
может быть вызвана разными способами, которые явно или неявно задают
начальное, конечное значения и шаг изменения счетчика цикла. В общем
случае, вызов выглядит следующим образом:
range(start, stop, step)
Такой вызов генерирует массив целых чисел от (включая) start
до
(не включая!) stop
с шагом step
, т.е. stop-1
--- последнее
целое значение. С использованием функции range
предыдущий пример
будет выглядеть так:
for i in range(3, 8, 1):
print i**2
По умолчанию, если функция range
вызывается с двумя параметрами,
они будут приняты в качестве start
и stop
, при этом
step=1
. Если задан только один аргумент, он используется в
качестве stop
. При этом шаг по умолчанию равен 1
, а значение
start
равно 0
. Таким образом, следующий вызов
range(6)
вернет целые числа 0, 1, 2, 3, 4, 5
.
Отметим, что можно сгенерировать убывающую последовательность целых
чисел, задав start > stop
и отрицательный шаг.
Модифициурем сценарий ball_plot.py из
раздела Программа на Python с векторизацией и построением графиков для иллюстрации использования цикла
for
. В том примере мы вычисляли высоту мяча в каждую миллисекунду
первой секунды его полета и строили график зависимости высоты от
времени.
Предположим, мы хотим найти максимальную высоту в течение этого времени. Один из вариантов реализации этого может быть следующим: вычисляем все тысяча значений высоты, сохраняем их в массив, а затем пробегаем весь массив, чтобы найти максимальное значение. Сценарий (max_height.py) может выглядеть так:
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
v0 = 5.0
g = 9.81
t = np.linspace(0, 1, 1000)
y = v0*t - 0.5*g*t**2
max_height = y[0]
for i in range(1, 1000):
if y[i] > max_height:
max_height = y[i]
print u'Максимальная достигнутая высота равна %f м' % (max_height)
plt.plot(t, y)
plt.xlabel(u'Время (с)')
plt.ylabel(u'Высота (м)')
plt.show()
Запуск программы даст
Максимальная достигнутая высота равна 1.274210 м
что хорошо согласуется с построенным графиком.
Иногда используются вложенные циклы, например в линейной
алгебре. Скажем, нам нужно найти максимум среди элементов матрицы
A
размера \( 4 \times 4 \). Фрагмент кода может выглядеть так:
max_number = A[0][0]
for i in range(4):
for j in range(4):
if A[i][j] > max_number:
max_number = A[i][j]
Следует отметить, что имя счетчика для каждого цикла из вложенных должно быть единственным. Кроме того, каждый вложенный цикл может содержать несколько строк кода как до, так и после следующего внутреннего цикла.
Векторизованные вычисления, которые мы использовали в
ball_plot.py из
раздела Программа на Python с векторизацией и построением графиков могли быть заменены обходом
массива t
и выполнением вычислений высоты по заданной формуле для
каждого элемента t
. Однако, следует знать, что векторизованные
вычисления выполняются гораздо быстрее.
while
В языке Python имеется еще одна стандартная циклическая конструкция
--- цикл while
. Для иллюстрации использования этого цикла
рассмотрим другую модификацию сценария ball_plot.py
из раздела. Теперь мы изменим его так, чтобы
сценарий находил время полета мяча. Предположим, что мы подбросили мяч
с немного меньшей начальной скоростью 4.5 м/с. Так как мы все
еще будем рассматривать первую секунду полета, то высота в конце этого
интервала будет отрицательной. Это означает, что мяч упал ниже
своего начального положения. В нашем массиве y
мы будем иметь ряд
отрицательных значений, которые расположены в конце массива. В
сценарии ball_time.py находится
момент времени, когда значение высоты становится отрицательным, т.е.,
когда мяч пересекается прямую \( y = 0 \). Сценарий может быть
следующим:
# -*- coding: utf-8 -*-
import numpy as np
v0 = 4.5
g = 9.81
t = np.linspace(0, 1, 1000)
y = v0*t - 0.5*g*t**2
i = 0
while y[i] >= 0:
i += 1
print u'y = 0 в момент времени ', 0.5*(t[i-1] + t[i])
import matplotlib.pyplot as plt
plt.plot(t, y)
plt.xlabel(u'Время (с)')
plt.ylabel(u'Высота (м)')
plt.show()
При выполнении сценария получим
y = 0 в момент времени 0.917417417417
В приведенном примере цикл while
выполняется до тех пор, пока
булевское выражение y[i] > 0
возвращает значение
True
. Отметим, что в этом случае счетчик цикла i
введен и
инициализирован (i = 0
) до начала выполнения цикла и обновляется
(i += 1
) внутри цикла. Таким образом, для каждой итерации i
явно увеличивается на 1.
В отличие от цикла for
, программист не должен определять
количество итераций при использовании цикла while
. Он просто
выполняется пока булевское выражение не вернет значение
False
. Таким образом, в этом случае счетчик цикла не
обязателен. Кроме того, если в цикле while
используется счетчик,
то он не увеличивается автоматически, это нужно делать явно. Конечно,
как и в цикле for
и в инструкции if
может быть несколько строк
кода в теле цикла while
. Любой цикл for
может быть реализован
с помощью while
, но циклы while
являются более общими и не все
из них можно реализовать с помощью for
.
Следует быть осторожным с так называемыми бесконечными
циклами. Могут возникнуть (непреднамеренно) случаи, когда тест в
инструкции while
никогда не вернет значение False
, и сценарий
не сможет выйти из цикла. Если вы случайно зациклите сценарий то можно
нажать комбинацию клавиш Ctrl-C
, чтобы остановить работу
сценария.
Как мы видели ранее набор чисел может хранится в массивах, которые мы можем обрабатывать целиком и поэлементно. В языке Python существует другой способ объединения данных, которые могут широко использоваться, как минимум не в вычислительных процедурах. К таким конструкциям относятся списки.
Списки очень похожи на массивы, но есть плюсы и минусы, которые стоит рассмотреть. Например, количество элементов списка может меняться, в то время как массивы имеют фиксированную длину, которую необходимо знать в момент выделения памяти. Элементы списка могут быть разных типов, в то время как элементы массива должны быть одного и того же типа. В общем случае, списки предоставляют большую гибкость, чем массивы. С другой стороны, массивы дают большую скорость вычислений, чем списки, что делает выбор массивов предпочтительным, если нет необходимости в гибкости, предоставляемой списками. Массивы также требуют меньше памяти и существует большое число готовых программ для различных математических вычислений. Векторизованные вычисления требуют использования массивов.
Функция range
на самом деле возвращает список. К элементу списка
можно обращаться как к элементу массива x[i]
. Как и для массивов
индексы элементов списка пробегают значения от 0
до
n-1
, если n
--- количество элементов списка. Можно
преобразовать список в массив следующим образом: x = array(L)
.
Список можно создать, например, так:
x = ['hello', 3, 3.15, 4]
В этом случае, x[0]
содержит строку hello
, x[1]
содержит
целое число 3
, x[2]
содержит действительное (float
) число
3.15
и т.д. Мы можем добавлять и удалять элементы массива, как
показано в следующем примере
x = ['hello', 3, 3.15, 4]
x.insert(0, -2) # x становится [-2, 'hello', 3, 3.15, 4]
del x[3] # x становится [-2, 'hello', 3, 4]
x.append(3.15) # x становится [-2, 'hello', 3, 4, 3.15]
Метод append
добавляет элемент в конец списка. Если необходимо,
можно создать пустой список x = []
а потом в цикле добавлять
элементы к списку. Чтобы узнать длину списка, можно воспользоваться
функцией len(x)
. Эта функция полезна, когда нам нужно обойти
список по индексам, так как функция range(len(x))
возвращает все
допустимые индексы.
Ранее мы видели обходить все элементы массива с помощью цикла
for
. Если нам нужно пробежать все элементы списка, мы можем
сделать это, как показано в следующем примере:
x = ['hello', 3, 3.15, 4]
for e in x:
print 'Элемент x: ', e
print `Это были все элементы списка x`
Как видно мы пробегаем элементы массива без использования
индексов. Следует понимать, что, когда мы так используем цикл, мы не
можем изменять значения элемента списка x
, изменяя e
. Это
означает, что, запись e += 2
ничего не изменит в списке x
, так
как e
используется только для чтения элементов списка.
В языке Python существует специальная конструкция, позволяющая пробежать все элементы списка, выполнить операцию с каждым элементом и сохранить новые элементы в другой список. Назовем эту конструкцию охват списка и проиллюстрируем примером:
List1 = [1, 2, 3, 4]
List2 = [e*10 for e in List1]
Этот фрагмент кода создает новый список List2
, содержащий элементы
10
, 20
, 30
и 40
. Выражение в квадратных скобках for e
in List1
означает, что будет последовательно пробегать все элементы
списка List1, и для каждого e
будет создан новый элемент списка
List2
со значением e*10
. В более общем случае:
List2 = [E(e) for e in List1]
где E(e)
означает любое выражение содержащее e
.
В некоторых случаях требуется одновременно пробегать 2 или более
списков. Python имеет удобную для этих целей функцию zip
. Пример
использования функции zip
будет дан ниже в сценарии
file_handle.py.
Также кратко упомянем кортежи, конструкции очень похожие на списки. Основное их отличие заключается в том, что кортежи не могут быть изменены. Новичкам может показаться странным, что такие "константные списки" могут быть даже предпочтительнее списков. Однако, свойство постоянности --- хорошая мера предосторожности от непреднамеренных изменений. Кроме того, в Python доступ к данным в кортежах быстрее, чем в списках, что способствует более быстрому коду. На основе примера, который был дан выше, мы можем создать кортеж и вывести на экран его содержимое:
x = ('hello', 3, 3.15, 4)
for e in x:
print 'Элемент x: ', e
print `Это были все элементы списка x`
Попытка использовать insert
или append
к кортежу выдаст
сообщение об ошибке, гласящую что объект типа кортеж не имеет таких
атрибутов.
Входные данные для программы часто можно получить из файла, а результаты вычислений часто нужно записывать в файл. Чтобы проиллюстрировать простейшую работу с файлами, рассмотрим пример, где читаются кооридинаты \( x \) и \( y \) из файла, содержащего две колонки, применяется функция \( f \) к \( y \), и записывается результат в новый файл с двумя колонками. Будем считать, что первая строка файла с данными --- это заголовок файла, который будем пропускать:
# координат x и y
1.0 3.0
2.0 3.9
3.0 5.3
4.0 6.0
Соответствующий сценарий на Python дан в файле file_handle.py
# -*- coding: utf-8 -*-
filename = 'data.txt'
infile = open(filename, 'r') # открытие файла для чтения
line = infile.readline() # чтение первой строки
# Чтение x и y из файла и сохранение их в списки
x = []; y = []
for line in infile:
words = line.split() # разбиение строки на слова
x.append(float(words[0]))
y.append(float(words[1]))
infile.close()
# Преобразование координаты y
from math import log
def f(y):
return log(y)
for i in range(len(y)):
y[i] = f(y[i])
# Запись x и y в файл из двух колонок
filename = 'tmp.txt'
outfile = open(filename, 'w') # открытие файла для записи
outfile.write('# координаты x и y\n')
for xi, yi in zip(x, y):
outfile.write('%10.5f %10.5f\n' % (xi, yi))
outfile.close()
Такие файлы, содержащие строку комментариев и колонки чисел,
достаточно часто используются при научных вычислениях. Поэтому в
numpy
реализован функционал облегчающий чтение и запись в такие
файлы. Ниже представлен пример, реализующий ту же функциональность,
что и предыдущий, с использованием функций loadtxt
и savetxt
из numpy
file_handle_np.py:
# -*- coding: utf-8 -*-
filename = 'data.txt'
import numpy as np
data = np.loadtxt(filename, comments="#")
x = data[:,0]
y = data[:,1]
data[:,1] = np.log(y)
filename = 'tmp.txt'
outfile = open(filename, 'w')
outfile.write('# координаты x и y\n')
np.savetxt(outfile, data, fmt='%10.5f')