Помимо использования встроенных функций языка Python и методов его классов, пользователь может создавать и использовать свои собственные функции.
Описание любой функции начинается со служебного слова def и имеет
следующий вид
def <имя функции>
([<параметры>]):
<блок>.
Функция может не иметь формальных параметров, иметь один такой параметр или несколько. Если
функция имеет несколько параметров, то они перечисляются через запятую.
Первой строкой блока функции может быть строка ее документирования
(docstring), которая берется в тройные кавычки и в среде IDLE появляется на экране в качестве
подсказки при вызове функции во время задания аргументов (см. также использование строки
документирования при объявлении классов в
подразделе 1.1 лаб. раб. №11).
Для возвращения значения функции используется оператор
return. Если возвращается несколько значений, то они должны быть указаны
в виде списка (см. раздел 2 лаб. раб. №3). Если
оператор return не задан в блоке функции или указан без операнда,
возвращается значение None
(см. встроенные типы в разделе 4 лаб. раб. №1).
Функцию можно определять в модуле, внутри другой функции
(см. подраздел 1.3) или в классе
(см. подраздел 1.1 лаб. раб. №11). Функция, определенная
в классе, называется методом.
Функции в языке Python являются объектами. С ними можно работать как и
с другими объектами языка. В этом состоит их отличие от функций в таких языках, как Java, C++ и C#.
При вызове фукнции указыается ее имя и в скобках – аргументы
(если функция их имеет). Число аргументов и их типы должны соответствовать числу и типам параметров
функции. При выполнении функции значения аргументов присваиваются соответствующим параметрам.
В качестве примера создания функции, рассмотрим задачу генерации
чисел Фибоначчи, уже приведенную в подразделе 6.3
лаб. раб. №1. Но теперь решение этой задачи реализуем в виде функции
fibo(k), которая определяет первые k чисел
Фибоначчи и возвращает их в виде списка:
>>>
def
fibo
(k):
'''Формирование чисел Фибоначчи (k – их количество)'''
a,b,i,f=0,1,0,[]
while
i<k:
f+=[b]
a,b=b,a+b
i+=1
return
f
Отметим, что созданная функция является объектом:
>>>
print
(
isinstance
(fibo, object))
True,
который можно вызвать по имени, потому что встроенная функция callable()
(см. раздел 8.1 лаб. раб. №1) возвращают значение
True:
>>>
print
(
callable
(fibo))
True,
и получить 10 чисел Фибоначчи:
>>>
print
(fibo(10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Функция fibo() оформлена в виде файла
. . . \LAB6\fibo.py, имеет один параметр
k, с помощью которого пользователь задает число необходимых ему
чисел Фибоначчи. В строке документирования указано назначение функции и ее параметра.
Имеется несколько способов передачи значений параметрам функции:
Позиционными являются такие аргументы функции, порядок которых при вызове функции строго
определен порядком параметров функции, т.е. их позицией. Нарушение порядка следования аргументов
(кроме отдельных случаев, когда порядок параметров неважен) приведет к нарушению правильной работы
функции (см. подраздел 1.1.2 ).
Рассмотрим пример создания функции, имеющей несколько позиционных
параметров:
>>>
def
val
(x, y, op):
if
op==
'+'
:
return
x+y
elif
op==
'-'
:
return
x-y
elif
op==
'*'
:
return
x*y
elif
op==
'/'
:
return
x/y
else
:
return
'Неверная операция'.
Параметры x и y
задают операнды, а op – одну из следующих арифметических операций:
сложение, вычитание, умножение или деление. Функция возвращает результат выполненной операции:
>>>
val(3, 2,
'+'
)
5
Если будет указана недопустимая операция
>>>
val(3, 2,
'//'
),
функция в качестве значения возвращает сообщение:
'Неверная операция'.
Как было указано в подразделе 1.1.1 в случае использования позиционных
аргументов существует опастность нарушения порядка следования аргументов при вызове функции,
например:
>>>
val(
'+'
, 3, 2)
'Неверная операция'
Чтобы этого не произошло, а также для более ясного текста программы,
в языке Python разрешено использовать именованные аргуметы, т.е. аргументы, в которых кроме
значения указывается также имя параметра. В таком случае при вызове функции аргументы могут быть
указаны в любом порядке:
>>>
val(op=
'+'
, x=3, y=2)
5
Отметим, что можно одновременно использовать именованные аргументы
и позиционные. Надо только следить за тем, чтобы справа от именованного аргумента были указаны
только именованные аргументы:
>>>
val(3,op=
'+'
, y=2)
5
В языке Python разрешено также использование аргументов с заданными по умолчанию значениями.
Это полезно делать в случаях, когда значения параметров изменяются достаточно редко. Например,
если функция val() (см. подраздел 1.1.1)
используется в основном для выполнения операции сложения, то ее параметры можно описать следующим
образом (остальная часть функции не изменилась):
>>>
def
val
(x, y, op=
'+'
):
Тогда для выполнения операции сложения при вызове функции третий
аргумент указывать не следует:
>>>
val(3, 2)
5
Если же функцию val() необходимо использовать
для умножения чисел, то тогда явно нужно указать третий параметр, значение которого переопределяет
значение, заданное по умолчанию:
>>>
val(3, 2,
'*'
)
6
Описание функции val() можно упростить и
расширить ее возможности, применив встроенную функцию eval()
(см. подраздел 4.3).
Python позволяет создавать функции с переменным числом значений аргументов. Для этого перед
именем парамера необходимо указать символ *. При вызове функции
переданные значения для данного параметра представляются в виде списка, т.е. в виде заключенной в
квадратные скобки последовательности данных, разделенных запятыми
(см. описание списков в разделе 2 лаб. раб. №3), элементы
которого можно обрабатывать в теле функции. В качестве примера приведем описание функции,
выполняющей сложение произвольного числа слагаемых:
>>>
def
sum1
(*args):
s=0
for
el
in
args:
s+=el
return
s
>>>
sum1(3,5,7,2)
17
Можно также, задав список значений:
>>>
a_list=[7,9,3,11]
вызвать функцию, указав в качестве аргумента имя списка с впереди стоящей звездочкой:
>>>
sum1(*a_list)
30
Другим вариантом создания функции с переменным числом аргументов является использование перед
именем парамера двух символов "звездочка" (**). В этом случае при вызове
функции переданные значения аргумента представляются в виде словаря
(см. описание словарей в разделе 2 лаб. раб. №5).
В качестве примера приведем описание функции list_of_keys(), имеющей два
аргумента – первый (позиционный) color указывает цвет, второй
**args указывает на аргумент в виде словаря. Функция просматривает
элементы словаря и сравнивает их значения с значением первого аргумента. При совпадении значений
ключ элемента словаря заносится в формируемый список ключей, который возвращает функция:
>>>
def
list_of_keys
(color, **args):
l_color=[]
for
k
in
args:
if
args[k]==color:
l_color+=[k]
return
l_color
>>>
a_dict={
'1'
:
'blue'
,
'2'
:
'blue'
,
'3'
:
'red'
,
'4'
:
'blue'
,
'5'
:
'green'
,
'6'
:
'green'
,
'7'
:
'blue'
}
>>>
list_of_keys(
'blue'
, **a_dict)
['1', '2', '7', '4']
lambda функции широко используются в языках функционального
программирования. Поэтому в языке Python осуществлена их поддержка:
>>>
def
f1
(n):
return
lambda
x:x**n
>>>
f2=f1(3)
>>>
f2(5)
125
Можно просто вызвать функцию f1:
>>>
f1(3)(5)
125
Использование lambda функции показано также
в подразделе 1.5.2.
Замыкание – это особый вид функции, которая определена в теле другой функции и создается
каждый раз при выполнении внешней функции. При этом вложенная внутренняя функция содержит ссылки на
локальные переменные внешней функции.
Ссылки на переменные внешней функции в случае замыкания действительны
внутри вложенной функции даже если внешняя функция завершила работу и переменные вышли из области
видимости. В объекте – функции привязаны к данным, в замыкании – данные привязаны
к функции.
Приведем пример простого замыкания:
>>>
def
make_add
(x):
def
add
(y):
return
x+y
return
add
>>>
make_add(2)(3)
5
Отметим, что в языке Python изменять значения можно только тех
переменных замыкания, которые относятся к изменяемым типам. Поэтому при выполнении примера, в
котором подчитывается число вызовов функции замыкания, заданного целочисленным типом :
>>>
def
create_counter
(count_calls=0):
def
change_counter
():
count_calls+=1
return
count_calls
return
change_counter
возникает ошибка:
nboundLocalError: local variable 'count_calls' referenced before assignment .
Исправить положение можно, задав число вызовов в виде элемента списка:
>>>
def
create_counter
(count_calls=[0]):
def
change_counter
():
count_calls[0]+=1
return
count_calls[0]
return
change_counter
>>>
create_counter()()
1
>>>
create_counter()()
2
>>>
create_counter()()
3.
Списки, помимо рассмотренных в разделе 2 лаб. раб. №3 методов,
также поддерживают метод sort(), который осуществляет сортировку
элементов списка. При использовании этого метода элементами списка могут быть только данные,
которые можно сравнивать между собой – числа или строки, причем список не должен содержать
сразу и числа и строки.
Необходимо отметить, что метод sort()
выполнив сортировку элементов списка, не возвращает результаты своей работы, точнее, всегда
возвращает значение None. Метод не имеет обязательных параметров –
если при его вызове аргументы не заданы, то элементы списка будут отсортированы по возростанию их
значений (строки сортируются по значению кодов их символов). Например:
>>>
a_list=[5,2.0,44,-3,27.5]
>>>
a_list.sort()
>>>
a_list
[-3, 2.0, 5, 27.5, 44],
>>>
b_list=[
'Python'
,
'cat'
,
'zz'
,
'A'
]
>>>
b_list.sort()
>>>
b_list
['A', 'Python', 'cat', 'zz'],
Два необязательных параметра предназначены для изменения порядка
сортировки:
Для использования параметра key необходимо разработать функцию,
которая преобразовывала бы элементы списка для сравнения. Например, для сортировкм слов не по
алфавиту, а по их длине, необходимо, чтобы функция возвращала их длину:
>>>
def
sort1
(item):
return
len
(item)
Теперь выполним сортировку слов списка, расположив их в порядке
уменьшения их длин:
>>>
b_list.sort(key=sort1, reverse=1)
>>>
b_list
['Python', 'cat', 'zz', 'A'],
Использование параметра key позволяет
осуществить сортировку списков, имеющих элементы разных типов. Пусть, например, список
c_list содержит числа, списки чисел и строки:
>>>
c_list=[6,
'Питон'
,[3,7,6],
'web'
,[1.6,20],0.67e1]
Использование метода sort() без аргументов
>>>
c_list.sort()
вызовет исключение
TypeError: unorderable types: int() < list()
,
т.е. элементы типов int и list нельзя сравнивать.
Для устранения этого ограничения разработаем функцию
sort2, которая анализирует тип элемента списка и возвращает следующие
значения:
>>>
def
sort2
(item):
if
isinstance
(item,
list
):
s=0
for
el
in
item:
s+=el
return
s/
len
(item)
elif
isinstance
(item,
str
):
return
ord
(item[0])
else
:
return
item
После вызова метода сортировки
>>>
c_list.sort(key=sort2)
получаем отсортированный список
>>>
c_list
[[3, 7, 6], 6, 6.7, [1.6, 20], 'web', 'Питон']
.
Чтобы сделать копию результата сортировки (без изменения самого
списка), необходимо вместо использования метода sort() применить
встроенную фукнцию sorted()
(см. подраздел 8.1 лаб. раб. №1), которая имеет те же
необязательные параметры:
>>>
d_list=sorted(c_list,key=sort2,reverse=1)
>>>
d_list
['Питон', 'web', [1.6, 20], 6.7, 6, [3, 7, 6]]
>>>
c_list
[[3, 7, 6], 6, 6.7, [1.6, 20], 'web', 'Питон']
Для фильтрации данных итерабельного типа может быть использована встроенная функция
filter(function, iterable)
(см. подраздел 8.1 лаб. раб. №1), которая возвращает итератор,
формируемый из тех элементов аргумента iterable, для которых второй аргумент – функция
function имеет значение True. В качестве примера рассмотрим задачу формирования простых чисел. Для формирования данных может быть использована встроенная функция
map(function,iterable)
(см. подраздел 8.1 лаб. раб. №1), которая имеет те же аргументы,
что и функция map(), но выполняет не фильтрацию, а формирование с помощью
функции function элементов итератора из элементов iterable. Оператор yield, используемый в теле функции, как и оператор
return завершает ее работу, но в отличие от оператора
return возвращает генератор. Рассмотрим еще раз задачу генерации кубов
чисел (см. подраздел 3.1 лаб. раб. №5), но теперь решим ее с
использованием оператора yield: Пространство имен представляет собой отображение имен (идентификаторов) в объекты. По
функциональности пространства имен эквивалентны словарям и реализуются в виде словарей. В языке
Python всегда присутствуют три пространства имен:
Важно понимать, что между именами в разных пространствах имен нет связи. Например, два модуля
могут определить функции с именем “max_item”, не создавая при этом путаницы – пользователь
должен ссылаться на них с использованием имени модуля в качестве префикса. Каждому Все переменные, созданные внутри функций (в том числе и параметры функций) являются локальными
переменными – их область видимости ограничивается описанием функции. Они невидимы вне
функций. Например, в функции f1() объявлена локальная переменная
var1. При попытке вывести на экран ее значение вне описания функции: Для получения пространства имен необходимо вызвать встроенную функцию
dir([object]), которая возвращает список имен, отсортированный по
алфавиту:
По умолчанию поведение функции dir() зависит от типа объектов:
При выполнении программы верхнего уровня текущей областью видимости будет текст модуля
__main__, загружаемый в память при вызове интерпретатора. Поэтому функция
dir(), вызванная без аргумента, возвратит список атрибутов этого модуля:
Добавим в программу оператор присваивания, задающий значение 25 глобальной переменной
x: Имена могут быть добавлены (только в локальное пространство имен) следующими способами:
Если глобальное имя не найдено в глобальном пространстве имен, его поиск производится в
пространстве встроенных имен, которое является пространством имен модуля
builtin. Этот модуль (или словарь определенных в нем имен) доступен
под глобальным именем текущего блока __builtins__. Если же имя не найдено
в пространстве встроенных имен, генерируется исключение NameError.
По мере возрастания сложности программ появляется необходимость разбить их на несколько файлов
для облегчения поддержки. Также может возникнуть необходимость в многократном использовании
написанных функций в нескольких программах, не копируя их определения в каждую из программ. Во всех
этих случаях оправдана разработка модулей. Модуль на языке Python – это файл с расширением .py, содержащий
описания функций, классов, переменные и другие объекты, как правило, общей области применения. Python позволяет во время работы программы динамически осуществлять компиляцию и выполнение
отдельных фрагментом кода. Для этого используются следующие встроенные функции
(см. подраздел 8.1) лаб. раб. №1):
Встроенная функция compile(source, filename, mode, flags=0,dont_inherit=False,
optimize=-1) – компилирует исходный код, указанный аргументом
source, в код или объект AST
(см. подраздел 8.1 лаб. раб. №1). Объекты кода могут
быть выполнены с помощью функций exec()
(см. подраздел 4.2 ) или eval()
(см. подраздел 4.3 ). Функция compile() вызывает исключение
SyntaxError, если компилируемый код неверен, и исключение
TypeError, если исходный код содержит байты null. Встроенная функция exec(object[, globals[, locals]]) поддерживает
динамическое выполнение кода языка Python
(см. подраздел 8.1 лаб. раб. №1). Аргумент
object должен быть строкой или объектом типа
code. Если это строка, то производится ее грамматический разбор, как это
делается с операторами языка. После чего происходит ее выполнение (до завершения или до появления
ошибки). Если это объект типа code, то он просто выполняется. Надо быть
готовым к тому, что операторы return и yield могут не выполняться вне определения функции даже
внутри контекста кода, передаваемого функции exec(). Возвращается
значение None. Аргументами встроенной функции
eval(expression, globals=None, locals=None)
(см. подраздел 8.1 лаб. работы №1) являются:
строка expression, задающая выражение, и необязательные словари
globals и locals, указывающие
пространства имен соответственно глобальных и локальных переменных
(см. подраздел 2.4 ). При выполнении функции осуществляется грамматический
разбор выражения и вычисление его значения: но
Сначала разработаем функцию simple(),
которая возвращает значение True, если ее аргументом является простое числом, и False – в
противном случае:
>>>
def
simple
(n):
for
_
in
range
(2,n):
if
n%_==0:
return False
return True
Функция simple(n) имеет параметр
n, являющийся целым числом, и проверяет остатки от деления этого числа
на числа от 2 до n-1. Если все отатки от деления не равны 0, т.е. число
n не делится нацело ни на одно из этих чисел и, следовательно, является
простым, то возвращается значение True. Иначе возращается значение False.
Теперь используем функции filter() и
simple() для формирования простых чисел в диапазоне от 2 до 100:
>>>
list
(
filter
(simple,rang(2,100)))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Функция filter() возвращает значения в виде
итератора, поэтому, так же как и для объектов типа range
(см. раздел 2 лаб. раб. №4), необходимо
конкретизовать с помощью конструктора тип данных, например, в виде списка.
1.5.2 Использование функции map()
В качестве примера рассмотрим формирование чисел вида
x*x-1, заданного lambda функцией
(см. подраздел 1.2 ), в диапазоне от 1 до 10, представленных в виде кортежа:
>>>
tuple
(
map
(
lambda
x:x*x-1,
range
(1,10)))
(0, 3, 8, 15, 24, 35, 48, 63, 80)
1.5.3 Использование оператора yield
>>>
def
create_gen
():
l=
range
(1,11)
for
x
in
l:
yield
x**3
>>>
my_gen=create_gen()
>>>
my_gen
<generator object create_gen at 0x01E2B030>
>>>
for
x
in
my_gen:
print
(x, end=
' '
)
1 8 27 64 125 216 343 512 729 1000 .
Начиная с версии 3.3 языка Python, появилась возможности делегировать
часть операций генератора другому генератору с помощью оператора
yield from. В качестве примера создадим функцию, которая формирует
генератор, состоящий из двух других генераторов, которые передают ему часть своих операций:
>>>
def
gen
(x):
yield from
range
(x,0,-1)
yield from
range
(x)
>>>
list
(gen(5))
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4].
2 Пространства имен и области видимости
2.1 Пространство имен
Под словом атрибут (англ. attribute) будет подразумеваться любое имя,
следующее после оператора точки: например, в выражении z.real,
real является атрибутом объекта z. Строго
говоря, имена в модулях являются атрибутами модуля: в выражении
mod_name.func_name, mod_name является
объектом-модулем и func_name является его атрибутом. В этом случае имеет
место прямое соответствие между атрибутами модуля и глобальными именами, определенными в модуле:
они совместно используют одно и то же пространство имен.
Пространства имен создаются в разные моменты времени и имеют разную
продолжительность жизни:
2.2 Область видимости
Необходимо подчеркнуть, что область видимости определяется по тексту:
глобальная область видимости функции, определенной в модуле соответствует пространству имен этого
модуля, независимо от того, откуда или под каким псевдонимом функция была вызвана.
Является ли имя локальным или глобальным определяется в момент
компиляции, т.е. статически: в отсутствии оператора global имя, добавляемое где-либо в блоке кода,
является локальным во всем блоке; все остальные имена считаются глобальными. Оператор global
заставляет интерпретатор считать указанные имена глобальными.
Несмотря на статическое определение, области видимости используются
динамически. В любой момент времени выполнения программы имеется ровно три вложенных области
видимости (три непосредственно доступных пространства имен). Сначала поиск имени производится во
внутренней области видимости, содержащей локальные имена. Далее – в средней, содержащей
глобальные имена модуля. И, наконец, во внешней, содержащей встроенные имена.
Обычно локальная область видимости соответствует локальному
пространству имен текущей функции (класса, метода). За пределами функции (класса, метода)
локальная область видимости соответствует тому же пространству имен, что и глобальная: пространству
имен текущего модуля.
2.3 Пространства имен и области видимости при описании функций
>>>
def
f1
():
var1=1
>>>
print
(var1)
происходит исключение
NameError: name 'var1' is not defined
Внутри функции переменная var1 доступна:
>>>
def
f1
():
var1=1
print
(var1)
>>>
f1()
1
Переменные, созданные в программе вне функций, являются глобальными
– они видимы везде в программе, включая области описания функций, т.е. они имеют глобальную
область видимости. Глобальные переменные доступны для чтения внутри функций:
>>>
def
f1
():
var1=1
print
(var1,var)
>>>
var=10
>>>
f1()
1 10
Однако попытка присвоить переменной var
в теле функции новое значение приведет к тому, что переменная с этим именем будет воспринята
интерпретатором как локальная переменная, которая будет иметь в своей локальной области видимости
это значение:
>>>
def
f1
():
var1=1
var=25
print
(var1,var)
>>>
var=10
>>>
f1()
1 25
Значение же глобальной переменной var
осталось неизменным:
>>>
print
(var)
10
Чтобы функция получила возможность изменять значение глобальной
переменной, необходимо использовать оператор global:
>>>
def
f1
():
global
var
var1=1
var=25
print
(var1,var)
>>>
var=10
>>>
f1()
1 25
>>>
print
(var)
25
2.4 Определение пространства имен в модулях и функциях
>>>
dir
()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
Поскольку в программе не были объявлены имена ни переменных, ни
функций, ни классов, то содержащиеся в списке атрибуты представляют собой пространство имен модуля
__main__, изначально для него заданное.
Для получения дополнительной информации можно вызвать встроенные
функции globals()
(см. подраздел 8.1 лаб. раб. №1) и
locals()
(см. подраздел 8.1 лаб. раб. №1), которые возвращают
соответственно глобальное и локальное пространства имен модуля в виде словарей, где ключи
представлены именами (те же имена, что возвращает функция dir()), а
значения – значениями соответствующих объектов:
>>>
globals
()
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__package__': None,
'__spec__': None}
>>>
loсals
()
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__package__': None,
'__spec__': None}
Также можно использовать встроенную функцию
vars()
(см. подраздел 8.1 лаб. раб. №1), которая возвращает
значение атрибута __dict__ для модуля, класса, экземпляра класса или других объектов, имеющих
атрибут __dict__:
>>>
vars
()
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__package__': None,
'__spec__': None}
Результаты работы функций globals(),
globals() и vars() показывают, что:
>>>
dir
(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError'
. . .
'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
(показаны только первая и последняя строки атрибутов);
>>>
x=25
25
И определим теперь пространство имен модуля:
>>>
dir
()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', 'builtins', 'x'].
Пространств имен модуля изменилось – к нему добавилось имя переменной
x. Имя этой переменной и ее значение добавились, естественно, и в словарь
глобальных имен модуля:
>>>
globals
()
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None,
'x': 25, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__package__': None,
'__spec__': None}
Добавим теперь в программу описание и вызов функции
func(), содержащей глобальную переменную y,
локальную переменную loc_x и вызовы функций
dir(), globals() и
locals() с выводом возвращаемых ими значений:
>>>
x=25
>>>
def
func
():
loc_x=100
global
y
y=7
print
(
dir
())
print
(
globals
())
print
(
locals
())
>>>
func()
['loc_x']
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__',
'func': <function func at 0x023A0588>, '__doc__': None, 'x': 25,
'__loader__': <lass '_frozen_importlib.BuiltinImporter'>, '__package__': None, '__spec__': None,
'y': 7}
{'loc_x': 100}
Результаты работы функции func()
показывают, что для локальной области видимости (блока функции):
3 Создание модулей пользователя
Модули выполняют как минимум три важных функции:
Программы на языке Python тоже представляют собой файлы с расширением
.py, но в отличие от модулей, которые используются для подключения к
другим программам, предназначены для непосредственного выполнения.
Для создания пользовательского модуля необходимо сформировать файл с
расширением .py, содержащий необходимые объекты. В качестве примера
создадим модуль с именем my_module в виде файла
my_module.py, куда запишем описание функции
fibo().
Для подключения созданного модуля к программе, как и любого другого
(см. раздел 1" лаб. раб. №2), используется оператор
import:
>>>
import
my_module
Оператор import позволяет также подключать
сразу несколько модулей, перечисляя из через запятую.
При вызове функции fibo() ее необходимо
указать как метод модуля my_module:
>>>
my_module.fibo(12)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
Непосредственный вызов функции
>>>
fibo(12)
вызовет исключение:
NameError: name 'fibo' is not defined
Это происходит потому, что пространство имен модуля не входит в
пространство имен программы. Для того, чтобы вызвать функцию fibo()
непосредственно, т.е. так, как если бы она была описана в самой программе, необходимо использовать
оператор from
>>>
from
my_module.fibo(12)
import
fibo
>>>
fibo(14)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
В операторе from можно задавать
одновременно сразу несколько объектов модуля, перечисляя их через запятую.
4 Компиляция и выполнение фрагментов кода
4.1 Функция compile()
Исходный код source может быть строкой
(см. раздел 2 лаб. раб. №2), типом bytes
(см. подраздел 3.1 лаб. раб. №4) или AST объектом
(для получения информации о том, как работать с AST объектами необходимо обратиться к документации
модуля ast).
Аргумент filename должен указывать имя
файла, откуда будет прочитан искодный код (если код находится в интерактивной среде разработки
– указывается значение '<string>').
Аргумент mode указывает вид кода, который
должен быть компилирован. Это может быть 'exec', если код состоит из
последовательности операторов (используется в большинстве случаев),
'eval' – если код состоит из единственного выражения (если указать
оператор, то возникнет исключение "invalid syntax"), или
'single', если код состоит из единственного оператора, используемого в
интерактивном режиме (если операторов больше – они не будут выполняться).
Необязательные аргументы flags и
dont_inherit определяют, какие операторы
future_statement
(см. PEP 236 http://legacy.python.org/dev/peps/pep-0236/) влияют на компилящию исходного кода.
Необязательный аргумент optimize указывает
уровень оптимизации компилятора. Значение, принимаемое по умолчанию (-1), выбирает уровень
оптимизации интерпретатора, заданный опцией -O. Явно задавать можно следующие уровни:
Отметим, когда компилируется строка, заданная на нескольких рядках, в
режимах 'single' или 'eval', ввод может быть
завершен даже одним символом перевода на новую строку (\n).
Изменения в версии 3.2: разрешается использование символов перевода на
новую строку в стиле Windows и Mac. Также ввод в режиме
'exec' больше не должен заканчиваться по символу перевода на новую строку.
Добавлен параметр оптимизации.
Приведем пример компиляции небольшого фрагмента кода:
>>>
my_code=
compile
(
'''
x=5
y=x**3+1
print(y) '''
,
'<string>'
,
'exec'
)
Переменная my_code указывает на
скомпилированный фрагмент кода. Определим ее тип:
>>>
type
(my_code)
<class 'code'>
Таким образом скомпилированный код имеет тип (класс)
code.
4.2 Функция exec()
Во всех случаях, когда необязательная часть аргументов опущена, код
выполняется в текущем пространстве имен. Если указан только аргумент globals,
должен быть словарь, который будет использоваться как для глобальных, так и для локальных
переменных. Если указаны аргуметры globals и locals, они будут
использованы соответственно для глобальных и локальных переменных. Если указан аргумент
locals, он может быть типа отображения. Необходимо помнить, что на уровне
модуля globals и locals являются одним и тем
же словарем. Если функция exec() получает два отдельных объекта –
globals и locals, код будет выполняться как
будто они были объявлены в определении класса.
Если словарь globals не содержит значение
для ключа__builtins__, ссылка на словарь встроенного модуля
builtins будет вставлена под этим ключем. Это можно контролировать,
поскольку builtins доступен выполняемому коду путем всключения
собственного словаря __builtins__ в пространство имен
globals перед передачей кода функции exec().
Отметим, во-первых, что встроенные функции
globals() и locals()
(см. подраздел 2.4 ) возвращают соответственно глобальный и локальный словари,
которые могут использоваться как второй и третий аргументы функции
exec().
Во-вторых, значения по умолчанию аргумента
locals() берутся так, как приведено в фукнции
locals(): модификации значений по умолчанию словаря
locals() не допускаются. Необходимо явно передать словарь
locals(), если нужно увидеть влияние кода на
locals() после того, как функция exec() вернет
значение.
Приведем два примера использования фукнции
exec(): один с аргументом в виде строки:
>>>
x=1.25
>>>
exec
(
'y=x*x+x+1'
)
>>>
y
3.8125
другой – с аргументом в виде скомпилированного кода. Для этого воспользуемся переменной
my_code, полученной в подразделе 4.1:
>>>
exec
(my_code)
126
4.3 Функция eval()
>>>
x=5
>>>
eval
(
'x+1'
,{
'x'
:1})
2
Если аргумент locals опущен, значения
берутся из словаря globals. Если опущены оба необязательных аргумента,
выражение вычисляется в том окружении, в котором функция eval() была
вызвана:
>>>
x=5
>>>
eval
(
'x+1'
)
6.
В подразделе 1.1.3 была рассмотрена функция
val(x, y, op), выполняющая заданные арифметические операции
(op) над двумя числами (x и
y). Использование функции eval() в блоке
функции val() (новый вариант функции –
new_val()) не только делает описание функции намного компактнее:
>>>
def
new_val
(x, y, op):
return
eval
(
str
(x)+op+
str
(y)),
>>>
new_val(3, 2, '/')
1.5,
но и любые двуместные операции для операндов x и
y:
>>>
new_val(3,2,'**')
9.
Причем даже такие, которых нет среди стандартных операций языка Python:
>>>
new_val(3, 2, '**2+')
11.
В заключение отметим, что eval(repr(object))
возвращает object. Например:
>>>
eval
(
repr
(
"cat"
))
'cat'.
Разработать программу на языке Python, в которой:
Номер п/п | Операция | Вид значений | Тип |
---|---|---|---|
1 | 1 | 5 | 1,5 |
2 | 2 | 4 | 2,3 |
3 | 3 | 3 | 2,4 |
4 | 4 | 2 | 2,5 |
5 | 5 | 1 | 3,4 |
6 | 6 | 5 | 3,5 |
7 | 7 | 4 | 1,5 |
8 | 1 | 3 | 2,3 |
9 | 2 | 2 | 2,4 |
10 | 3 | 1 | 2,5 |
11 | 4 | 5 | 3,4 |
12 | 5 | 4 | 3,5 |
13 | 6 | 3 | 1,5 |
14 | 7 | 2 | 2,3 |
15 | 1 | 1 | 2,4 |
16 | 2 | 5 | 2,5 |
17 | 3 | 4 | 3,4 |
18 | 4 | 3 | 3,5 |
19 | 5 | 2 | 1,5 |
20 | 6 | 1 | 2,3 |