Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ЛЕКЦИЯ 6

.pdf
Скачиваний:
14
Добавлен:
26.03.2016
Размер:
1.66 Mб
Скачать

2.5. Инструкция global.

Инструкция global и родственная ей инструкция nonlocal – единственные инструкции в языке Python, отдаленно напоминающие инструкции объявления. Однако они не объявляют тип или размер – они объявляют пространства имен.

Глобальные имена – это имена, которые определены на верхнем уровне вмещающего модуля.

Глобальные имена должны объявляться, только если им будут присваиваться значения внутри функций.

Обращаться к глобальным именам внутри функций можно и без объявления их глобальными.

X = 88 # Глобальная переменная X def func():

global X # Глобальная переменная X: за пределами инструкции def X = 99

func()

print(X) # Выведет 99

–------------------------------------------------------------ y, z = 1, 2

def all_global(): global x

x = y + z print(x) # Выведет 3

Минимизируйте количество глобальных переменных.

X = 99

def func1(): global X X = 88

def func2(): global X

X = 77

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

Минимизируйте количество изменений в соседних файлах.

# first.py

X = 99 # Этот программный код не знает о существовании second.py

# second.py import first

print(first.X) # Нет ничего плохого в том, чтобы обратиться

# к имени в другом файле

first.X = 88 # Но изменение может привести к сложностям Лучше добавить функцию доступа: # first.py

X = 99

def setX(new): global X X = new

# second.py

import first first.setX(88)

2.6.Области видимости и вложенные функции.

При обращении к переменной (X) поиск имени X сначала производится в локальной области видимости (функции); затем в локальных областях видимости всех лексически объемлющих функций, изнутри наружу; затем в текущей глобальной области видимости (в модуле); и, наконец, во встроенной области видимости (модуль builtins).

Поиск имен, объявленных в инструкции global, начинается сразу с глобальной (в модуле) области видимости.

Операция присваивания (X = value) по умолчанию создает или изменяет имя X в текущей локальной области видимости.

Если имя X объявлено глобальным внутри функции, операция присваивания создает или изменяет имя X в области видимости объемлющего модуля.

Если имя X объявлено нелокальным внутри функции, операция присваивания создает или изменяет имя X в ближайшей области видимости объемлющей функции.

X = 99 # Имя в глобальной области: не используется def f1():

X = 88 # Локальное имя в объемлющей функции def f2():

print(X) # Обращение ̆во вложенной функции f2()

f1() # Выведет 88: локальная переменная в объемлющей функции

def f1(): X = 88

def f2():

print(X) # Сохраняет X в объемлющей области return f2 # Возвращает f2, но не вызывает ее

action = f1() # Создает и возвращает функцию action() # Вызов этой функции: выведет 88

2.7. Инструкция nonlocal.

Эта инструкция позволяет вложенным функциям изменять переменные, которые определены в областях видимости

синтаксически объемлющих функций.

 

def tester(start):

 

state = start # Обращение к нелокальным переменным

>>> F = tester(0)

def nested(label): # действует как обычно

>>> F(‘spam’)

print(label, state) # Извлекает значение state из области

spam 0

return nested # видимости объемлющей функции

>>> F(‘ham’)

 

Ham 0

Если переменную state, локальную для функции tester, объявить в функции nested с помощью инструкции nonlocal, мы сможем изменять ее внутри функции nested:

def tester(start):

state = start # В каждом вызове сохраняется свое значение state def nested(label):

nonlocal state # Объект state находится

print(label, state) # в объемлющей области видимости

state += 1 # Изменит значение переменной, объявленной как nonlocal return nested

>>>F = tester(0)

>>>F(‘spam’) # Будет увеличивать значение state при каждом вызове spam 0

>>> F(‘ham’)

>>> F(‘eggs’)

ham 1

eggs 2

3.Аргументы.

Аргументы передаются через автоматическое присваивание объектов локальным переменным.

Аргументы функции – ссылки на объекты. Сами объекты никогда не копируются автоматически.

Операция присваивания именам аргументов внутри функции не оказывает влияния на вызывающую программу. При вызове функции имена аргументов, указанные в ее заголовке, становятся новыми локальными именами в области видимости функции.

Неизменяемые объекты передаются «по значению». Такие объекты, как целые числа и строки, передаются в виде ссылок на объекты, но так как неизменяемые объекты невозможно изменить непосредственно, передача таких объектов очень напоминает копирование.

Изменяемые объекты передаются «по указателю». Такие объекты, как списки и словари, также передаются в виде ссылок на объекты, что очень похоже на то, как в языке C передаются указатели на массивы, – изменяемые объекты допускают возможность непосредственного изменения внутри функции так же, как и массивы в языке C. Изменяемые объекты могут рассматриваться функциями как средство ввода, так и вывода информации.

def changer(a, b): # В аргументах передаются ссылки на объекты a= 2 # Изменяется только значение локального имени

b[0] = ‘spam’ # Изменяется непосредственно разделяемый объект

>>X = 1

>>L= [1,2] # Вызывающая программа

>>changer(X, L) # Передаются изменяемый и неизменяемый объекты

>>X,L # Переменная X – не изменилась, L — изменилась

(1, [‘spam’, 2])

4.Концепции проектирования функций.

Взаимодействие: для передачи значений функции используйте аргументы, для возврата результатов – инструкцию return. Всегда следует стремиться сделать функцию максимально независимой от того, что происходит

за ее пределами. Аргументы и инструкция return часто являются лучшими способами ограничить внешнее воздействие небольшим числом известных мест в программном коде.

Взаимодействие: используйте глобальные переменные, только если это действительно необходимо.

Глобальные переменные (то есть имена в объемлющем модуле) обычно далеко не самый лучший способ организации взаимодействий с функциями. Они могут порождать зависимости и проблемы согласованности, которые существенно осложняют отладку программ.

Взаимодействие: не воздействуйте на изменяемые аргументы, если вызывающая программа не предполагает этого. Функции могут оказывать воздействие на части изменяемых объектов - аргументов, но, как и

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

Связность: каждая функция должна иметь единственное назначение. Хорошо спроектированная функция должна решать одну задачу, которую можно выразить в одном повествовательном предложении. Если это предложение допускает слишком широкое толкование (например: «эта функция реализует всю программу целиком») или содержит союзы (например: «эта функция дает возможность клиентам составлять и отправлять заказ

на доставку пиццы»), то стоит подумать над тем, чтобы разбить ее на отдельные и более простые функции. В противном случае окажется невозможным повторно использовать программный код функции, в котором смешаны различные действия.

Размер: каждая функция должна иметь относительно небольшой размер. Это условие естественным образом следует из предыдущего, однако если функция начинает занимать несколько экранов – это явный признак, что пора подумать о том, чтобы разбить ее. Особенно, если учесть краткость, присущую языку Python.

4.Концепции проектирования функций.

Взаимодействие: избегайте непосредственного изменения переменных в другом модуле. Непосредственное

изменение переменных в других модулях устанавливает тесную зависимость между модулями, так же как тесную зависимость устанавливает изменение глобальных переменных из функций – модули становятся сложными в

понимании и малопригодными для многократного использования. Всегда, когда это возможно, для изменения переменных модуля вместо прямых инструкций присваивания используйте функции доступа.

5.Рекурсивные функциии.

Рекурсивные функции – функции, которые могут вызывать сами себя, прямо или косвенно, образуя цикл.

Это полезный прием, позволяющий реализовывать обход структур данных с произвольной и неизвестной заранее организацией.

Рекурсия является альтернативой простым циклам и итерациям, хотя и не обязательно более простой или более производительной.

def mysum(L):

print(L) # Поможет отслеживать уровни рекурсии

if not L: # На каждом уровне список L будет получаться короче return 0

else:

return L[0] + mysum(L[1:]) # Вызывает себя саму

>>mysum([1, 2, 3, 4, 5])

[1,2, 3, 4, 5] [2, 3, 4, 5] [3, 4, 5] [4, 5] [5] [ ] 15

5. Рекурсивные функциии.

def mysum(L):

return 0 if not L else L[0] + mysum(L[1:]) # Трехместный оператор

def mysum(L): # Суммирует любые типы

return L[0] if len(L) == 1 else L[0] + mysum(L[1:]) # предполагает наличие хотя бы одного значения

def mysum(L):

# Использует расширенную

first, *rest = L

# операцию присваивания последовательностеи ̆

return first if not rest else first + mysum(rest)

 

>>>mysum([1]) # mysum([]) будет завершаться ошибкой в 2 последних функциях 1

>>>mysum([1, 2, 3, 4, 5])

15

>>>mysum((‘s’, ‘p’, ‘a’, ‘m’)) # Но они могут суммировать данные любых типов ‘spam’

>>>mysum([‘spam’, ‘ham’, ‘eggs’])

‘spamhameggs’

5.1. Применение рекурсии.

Рассмотрим задачу вычисления суммы всех чисел в структуре, состоящей из вложенных списков:

[1, [2, [3, 4], 5], 6, [7, 8]] # Произвольно вложенные списки

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

def sumtree(L): tot = 0

for x in L: # Обход элементов одного уровня if not isinstance(x, list):

tot += x # Числа суммируются непосредственно else:

tot += sumtree(x) # Списки обрабатываются рекурсивными вызовами return tot

L = [1, [2, [3, 4], 5], 6, [7, 8]] # Произвольная глубина вложения print(sumtree(L)) # Выведет 36

# Патологические случаи

print(sumtree([1, [2, [3, [4, [5]]]]])) # Выведет 15 (центр тяжести справа) print(sumtree([[[[[1], 2], 3], 4], 5])) # Выведет 15 (центр тяжести слева)