Главная страница

Пособие. Пособие по Python. Название Описание


Скачать 0.75 Mb.
НазваниеНазвание Описание
АнкорПособие
Дата05.10.2021
Размер0.75 Mb.
Формат файлаpdf
Имя файлаПособие по Python.pdf
ТипДокументы
#241608
страница4 из 5
1   2   3   4   5
print
(
"---------------"
) sayHello()
Здесь будет уже два вызова этой функции. И так далее. Причем, обратите внимание, мы вызываем функцию только после ее определения. То есть, если записать ее вызвать в самом начале программы, то возникнет ошибка, т.к. данная функция не была определена. Это вроде как:
"сначала нужно испечь пирог и только потом можно его есть."
Также и с функциями: мы их сначала определяем и только потом можем вызывать. Поэтому определение функций обычно идет в самом начале, а потом уже их вызовы в основной программе.
Если нужно определить еще одну функцию, то мы ее можем записать после первой:
def
myAbs(x): x
=
-x
if
(x
<
0
)
else
x
Имена функций должны быть уникальными (также как и имена переменных), поэтому я назвал ее myAbs, т.к. функция abs уже существует. И предполагаю, что она будет вычислять модуль переданного ей числа. Соответственно, в круглых скобках обозначаю этот аргумент. Если теперь мы ее вызовем:
print
( myAbs(-
5
) ) то увидим значение None. Это произошло потому, что функция myAbs явно не возвращает никакого значения. По идее, мы ожидаем возврата переменной x. Для этого нужно записать оператор return, после которого через пробел указываем возвращаемую величину:

def
myAbs(x): x
=
-x
if
(x
<
0
)
else
x
return
x
Теперь, при вызове функции, получим ожидаемое значение 5. Как это в деталях работает? Вызывая функцию с аргументом -5, переменная x начинает ссылаться на этот числовой объект. Далее, выполняется тело функции и идет проверка: если x<0, то x=-x (меняем знак числа), иначе x не меняется. Затем, выполняется оператор return и функция myAbs возвращает вычисленное значение x.
Такой подход позволяет передавать функции самые разные значения, например, так:
print
( myAbs(
15
) ) a
=
100
print
( myAbs(a) )
И это делает ее работу универсальной – с любыми числовыми данными. Причем, как только встречается оператор return функция завершает свою работу. То есть, если после данного оператора будут идти еще какие-либо конструкции:
def
myAbs(x): x
=
-x
if
(x
<
0
)
else
x
return
x
print
(x)
То при вызове этой функции: val
=
myAbs(-
5.8
)
Ничего в консоль выведено не будет, т.к. вызов был завершен на операторе return. А вот если поставить print до этого оператора:
def
myAbs(x): x
=
-x
if
(x
<
0
)
else
x
print
(x)
return
x то мы увидим значение 5.8. Используя эту особенность, можно определять такие функции:
def
isPositive(x):
if
x
>=
0
:
return
True

else
:
return
False
В данном случае мы будем получать значения True для неотрицательных чисел и False – для отрицательных. И далее, ее можно использовать так: p
=
[]
for
a
in
range
(-
5
,
11
):
if
isPositive(a): p.append(a)
print
(p)
В результате, список будет содержать только положительные числа.
Правда, в данном случае, функцию можно записать гораздо короче:
def
isPositive(x):
return
x
>=
0
Здесь сам оператор >= будет возвращать значение True или False.
Если нужно создать функцию, принимающую два аргумента, например, для вычисления площади прямоугольника, то это делается так:
def
getSquare(w
,
h):
return
2
*(w+h)
То есть, аргументы перечисляются через запятую, а тело функции состоит всего из одного оператора return, в котором сразу выполняются необходимые вычисления.
Вызовем эту функцию: p
=
getSquare(
10
,
5.5
)
print
(p)
И увидим результат ее работы – значение 31,0. При этом, на первое значение 10 ссылается первый аргумент w, а на второе 5.5 – второй аргумент h. Вот так можно определять различное число аргументов у функций.
Далее, при вызове функций мы должны им передавать ровно столько параметров, сколько указано в их определении. Например, вот такие вызовы работать не будут:
myAbs() myAbs(
1
,
2
) sayHello(
"abc"
)
Здесь указано или слишком много, или слишком мало фактических
параметров.
Однако у любой функции можно добавить формальные
параметры со значениями по умолчанию:
def
sayHello(msg
,
end
=
"!"
):
print
(msg+end)
И теперь, можно вызвать эту функцию так: sayHello(
"Hello"
) или так: sayHello(
"Hello"
,
"?"
)
Смотрите, если формальный параметр не указан, то берется его значение по умолчанию. Если же мы его явно задаем, то берется переданное значение. Здесь нужно помнить только одно правило: формальные аргументы должны быть записаны последними в списке аргументов функции. То есть, вот такая запись:
def
sayHello(end
=
"!"
,
msg): приведет к синтаксической ошибке.
Теперь, давайте добавим этой функции еще один вот такой формальный параметр:
def
sayHello(msg
,
end
=
"!"
,
sep
=
": "
):
print
(
"Message"
+sep+msg+end)
И функция будет выводить сообщение в формате:
«Message»+sep+msg+end. Вызвать эту функцию мы можем таким образом: sayHello(
"Hello"
,
"?"
,
" "
) и каждому параметру здесь будет соответствовать свое значение в соответствии с указанным порядком. А можно ли вызвать эту функцию, указав только первый и последний аргумент? Оказывается да, Python позволяет это делать. Вот таким образом:
sayHello(
"Hello"
,
sep
=
" "
)
Мы здесь вторым аргументом явно указываем имя формального параметра и присваиваем ему желаемое значение. В результате аргументы msg и sep будут принимать переданные значения, а аргумент end – значение по умолчанию. Это называется именованные параметры, когда мы указываем не просто значение, но еще и имя параметра.
Если нам требуется сразу вернуть несколько значений, то это можно сделать так. Предположим наша функция будет сразу определять и периметр и площадь прямоугольника:
def
perAndSq(w
,
h):
return
2
*(w+h)
,
w*h
И, далее, вызываем ее: res
=
perAndSq(
2.3
,
5
)
print
(res) получаем результат в виде кортежа из двух чисел. Или, так: per
,
sq
=
perAndSq(
2.3
,
5
)
print
(per
,
sq)
Аналогичным образом можно возвращать и списки и словари и вообще любые типы данных.
Далее, в теле функции можно записывать самые разные конструкции языка Python. Например, для возведения числа в целую степень, можно определить такую функцию:
def
myPow(x
,
n): sx
=
1
while
n
>
0
: sx *
=
x n -
=
1
return
sx
И, затем, вызвать ее: p
=
myPow(
3
,
5
)
print
(p)

Интересной особенностью Python в определении функций является возможность переопределять уже существующие функции. Например, у нас задана вот такая функция:
def
sayHello():
print
(
"hello"
)
Тогда ниже мы можем ее переопределить, если укажем то же самое имя:
def
sayHello():
print
(
"------- hello --------"
)
Теперь, при ее вызове: sayHello() увидим выполнение последнего, переопределенного варианта. Если дальше ее переопределить вот так:
def
sayHello(msg):
print
(msg) то все равно будет доступна только одна такая функция, но теперь уже с одним обязательным аргументом: sayHello(
"привет мир"
)
Когда это может пригодиться на практике? Например, если мы хотим определить некоторую функцию в зависимости от условия:
TYPE_FUNC
=
True
if
TYPE_FUNC:
def
sayHello():
print
(
"hello"
)
else
:
def
sayHello(msg):
print
(msg) sayHello()
Здесь при значении переменной TYPE_FUNC равной True будет определен первый вариант функции, а иначе – второй вариант.
Иногда это бывает полезно.

Элементы функционального подохда к программированию
При написании программ приветствуется такой подход, который называется функциональным программированием.
Продемонстрирую его на следующем примере. Предположим, нам нужна функция, которая находит максимальное значение из двух чисел:
def
max2(a
,
b):
if
a
>
b:
return
a
return
b
И вызвать мы ее можем так:
print
( max2(
2
,
-
3
) )
Затем, нам потребовалась функция, которая бы находила максимальное из трех чисел. Как ее можно реализовать? Используя идею функционального программирования, это можно сделать следующим образом:
def
max3(a
,
b
,
c):
return
max2(a
,
max2(b
,
c))
И вызвать так:
print
( max3(
2
,
-
3
,
5
) )
Смотрите, здесь оператор return возвращает значение, которое возвращает функция max2. Но, прежде чем она будет выполнена, вызовется другая функция max2, которая определит максимальное среди чисел b и c. То есть, прежде чем вызвать первую функцию max2 необходимо вычислить ее параметры: первый просто берется их x, а второй вычисляется вложенной функцией max2. Вот так это работает и вот что из себя представляет элемент функционального подхода к программированию.
Причем, благодаря гибкости языка Python, мы можем вызвать эту функцию и для нахождения максимальной строки:
print
( max3(
"ab"
,
"cd"
,
"abc"
) ) так как строки могут спокойно сравниваться между собой. И вообще, любые величины, которые можно сравнивать на больше и меньше, можно подставлять в качестве аргументов функции max3 и max2.
как в Python можно считывать информацию из файлов и записывать ее в файлы. Что такое файлы и зачем они нужны, думаю объяснять не надо, т.к. если вы дошли до этого занятия, значит, проблем с пониманием таких базовых вещей у вас нет. Поэтому сразу перейдем к функции open(file [, mode=’r’, encoding=None, …]) через которую и осуществляется работа с файлами. Здесь
• file
– это путь к файлу вместе с его именем;
• mode
– режим доступа к файлу;
• encoding
– кодировка файла.
Для начала определимся с понятием «путь к файлу». Представим, что наш файл ex1.py находится в каталоге app:
Тогда, чтобы обратиться к файлу my_file.txt путь можно записать так:
"my_file.txt" или "d:\\app\\my_file.txt" или так:
"d:/app/my_file.txt"
Последние два варианта представляют собой абсолютный путь к файлу, то есть, полный путь, начиная с указания диска. Причем, обычно используют обратный слеш в качестве разделителя: так короче писать и такой путь будет корректно восприниматься как под
ОС Windows, так и Linux. Первый же вариант – это относительный путь, относительно рабочего каталога.

Теперь, предположим, мы хотим обратиться к файлу img.txt. Это можно сделать так:
"images/img.txt" или так:
"d:/app/images/img.txt"
Для доступа к out.txt пути будут записаны так:
"../out.txt"
"d:/out.txt"
Обратите внимание, здесь две точки означают переход к родительскому каталогу, то есть, выход из каталога app на один уровень вверх.
И, наконец, для доступа к файлу prt.dat пути запишутся так:
"../parent/prt.dat"
"d:/ parent/prt.dat"
Вот так следует прописывать пути к файлам. В нашем случае мы имеем текстовый файл «myfile.txt», который находится в том же каталоге, что и программа ex1.py, поэтому путь можно записать просто указав имя файла: file
=
open
(
"myfile.txt"
)
В результате переменная file будет ссылаться на файловый объект, через который и происходит работа с файлами. Если указать неверный путь, например, так: file
=
open
(
"myfile2.txt"
) то возникнет ошибка FileNotFoundError. Это стандартное исключение и как их обрабатывать мы с вами говорили на предыдущем занятии.
Поэтому, запишем этот критический код в блоке try:
try
: file
=
open
(
"myfile2.txt"
)
except
FileNotFoundError:
print
(
"
Невозможно открыть файл"
)

Изменим имя файла на верное и посмотрим, как далее можно с ним работать. По умолчанию функция open открывает файл в текстовом режиме на чтение. Это режим mode = "r"
Если нам нужно поменять режим доступа к файлу, например, открыть его на запись, то это явно указывается вторым параметром функции open:
file
=
open
(
"out.txt"
,
"w"
)
В Python имеются следующие режимы доступа:
Название Описание 'r' открытие на чтение (значение по умолчанию)
'w' открытие на запись (содержимое файла удаляется, а если его нет, то создается новый)
'x' открытие файла на запись, если его нет генерирует исключение 'a' открытие на дозапись (информация добавляется в конец файла)
Дополнения 'b' открытие в бинарном режиме доступа к информации файла 't' открытие в текстовом режиме доступа (если явно не указывается, то используется по умолчанию)
'+' открытие на чтение и запись одновременно
Здесь мы имеем три основных режима доступа: на чтение, запись и добавление. И еще три возможных расширения этих режимов, например,

'rt'
– чтение в текстовом режиме;

'wb'
запись в бинарном режиме;

'a+'
– дозапись или чтение данных из файла.
Чтение информации из файла
В чем отличие текстового режима от бинарного мы поговорим позже, а сейчас откроем файл на чтение в текстовом режиме: file
=
open
(
"myfile.txt"
)
и прочитаем его содержимое с помощью метода read:
print
( file
.read() )
В результате, получим строку, в которой будет находиться прочитанное содержимое. Действительно, в этом файле находятся эти строчки из поэмы Пушкина А.С. «Медный всадник». И здесь есть один тонкий момент. Наш текстовый файл имеет кодировку Windows-
1251 и эта кодировка используется по умолчанию в функции read. Но, если изменить кодировку файла, например, на популярную UTF-8, то после запуска программы увидим в консоли вот такую белиберду. Как это можно исправить, не меняя кодировки самого файла? Для этого следует воспользоваться именованным параметром encoding и записать метод open вот так: file
=
open
(
"myfile.txt"
,
encoding
=
"utf-8"
)
Теперь все будет работать корректно. Далее, в методе read мы можем указать некий числовой аргумент, например,
print
( file
.read(
2
) )
Тогда из файла будут считаны первые два символа. И смотрите, если мы запишем два таких вызова подряд:
print
( file
.read(
2
) )
print
( file
.read(
2
) ) то увидим, что при следующем вызове метод read продолжил читать следующие два символа. Почему так произошло? Дело в том, что у файлового объекта, на который ссылается переменная file, имеется внутренний указатель позиции (file position), который показывает с какого места производить считывание информации.

Когда мы вызываем метод read(2) эта позиция автоматически сдвигается от начала файла на два символа, т.к. мы именно столько считываем. И при повторном вызове read(2) считывание продолжается, т.е. берутся следующие два символа. Соответственно, позиция файла сдвигается дальше. И так, пока не дойдем до конца.
Но мы в Python можем управлять этой файловой позицией с помощью метода seek(offset[, from_what])
Например, вот такая запись: file
.seek(
0
) будет означать, что мы устанавливаем позицию в начало и тогда такие строчки:
print
( file
.read(
2
) ) file
.seek(
0
)
print
( file
.read(
2
) ) будут считывать одни и те же первые символы. Если же мы хотим узнать текущую позицию в файле, то следует вызвать метод tell: pos
=
file
.tell()
print
( pos )
Следующий полезный метод – это readline позволяет построчно считывать информацию из текстового файла:
s
=
file readline
()
print
( s )
Здесь концом строки считается символ переноса ‘\n’, либо конец файла. Причем, этот символ переноса строки будет также присутствовать в строке. Мы в этом можем убедиться, вызвав дважды эту функцию:
print
( file readline
() )
print
( file readline
() )
Здесь в консоли строчки будут разделены пустой строкой. Это как раз из-за того, что один перенос идет из прочитанной строки, а второй добавляется самой функцией print. Поэтому, если их записать вот так:
print
( file readline
()
,
end
=
""
)
print
( file readline
()
,
end
=
""
) то вывод будет построчным с одним переносом.
Если нам нужно последовательно прочитать все строчки из файла, то для этого обычно используют цикл for следующим образом:
for
line
in
file
:
print
( line
,
end
=
""
)
Этот пример показывает, что объект файл является итерируемым и на каждой итерации возвращает очередную строку.
Или же, все строчки можно прочитать методом s
=
file
.readlines() и тогда переменная s будет ссылаться на упорядоченный список с этими строками:
print
( s )
Однако этот метод следует использовать с осторожностью, т.к. для больших файлов может возникнуть ошибка нехватки памяти для хранения полученного списка.
По сути это все методы для считывания информации из файла. И, смотрите, как только мы завершили работу с файлом, его следует закрыть. Для этого используется метод close: file
.close()

Конечно, прописывая эту строчку, мы не увидим никакой разницы в работе программы. Но, во-первых, закрывая файл, мы освобождаем память, связанную с этим файлом и, во-вторых, у нас не будет проблем в потере данных при их записи в файл. А, вообще, лучше просто запомнить: после завершения работы с файлом, его нужно закрыть. Причем, организовать программу лучше так:
1   2   3   4   5


написать администратору сайта