Неужели не нашлось русских специалистов, чтобы записать курс по пайтону ? Да, можно включить переводчик и слушать с переводом, но это что? Это кто-то считает хорошим и понятным курсом для начинающих? |
Модульное программирование: атрибуты и методы
Смотреть на youtube
Подводя некоторые итоги, можно отметить, что модуль является контейнером, который может содержать:
- данные, представленные атрибутами модуля,
- методы, задающие сервисы, предоставляемые модулем,
- выполняемый код.
Ни одна из этих частей модуля не является обязательной. Позже мы подробно обсудим, в каких ситуациях следует проектировать ту или иную структуру модуля, а сейчас же займемся деталями того, как взаимодействуют различные компоненты модуля.
В предыдущей лекции мы говорили, что атрибуты модуля - это глобальные переменные, видимые во всем модуле, потому доступные всем методам. Это позволяет методу всю необходимую информация или часть ее получать не через механизм формальных - фактических параметров, а через атрибуты модуля. Это особенно удобно, когда разным методам необходима одна и та же информация. Такой способ передачи входной информации методу позволяет также уменьшить число параметров, передаваемых при вызове метода.
А может ли метод передать информацию глобальным переменным модуля? Могут ли методы модуля обмениваться информацией, используя глобальные переменные. Ответ - да, могут, но есть одна проблема. Пусть X - имя глобальной переменной, введенное в модуле, Y - локальная переменная, определенная в теле метода. Тогда в теле метода присваивание Y = X допустимо, и локальная переменная Y станет ссылкой на объект, связанный с глобальной переменной. Присваивание X = Y также допустимо, но по правилам Python в теле метода появится локальная переменная с именем X и она станет ссылкой на объект, связанный с локальной переменной Y. На атрибут модуля X присваивание в теле метода никак не повлияет. Так что напрямую изменять атрибуты в теле метода прямым присваиванием нового значения невозможно. Тем не менее есть два способа справиться с поставленной задачей. Первый из них хорошо знаком и подробно обсуждался, когда мы рассматривали процедуру сортировки списка. Напомню: "не продается вдохновенье, но можно рукопись продать". Нельзя изменить связь между именем и объектом, но можно изменить сам объект. Нельзя атрибуту в теле метода присвоить новое значение, но можно изменить объект, связанный с атрибутом. Рассмотрим пример:
#Пример метода reverse, получающего информацию от атрибута Arr и изменяющего его состояние Arr = [5, 7, 3, 15, 8] def reverse(): n = len(Arr) i = 0; j = n - 1 while(i < j): Arr[i], Arr[j] = Arr[j], Arr[i] i = i + 1; j = j - 1 def test3(): print ('Arr before reverse:', Arr ) reverse() print ('Arr after reverse:', Arr ) test3()
Как видите, метод reverse не имеет параметров, получая информацию от атрибута Arr. Но метод не только получает информацию от атрибута, - он изменяет состояние объекта, связанного с атрибутом.
Существует способ, когда изменить атрибут можно прямым присваиванием. Чтобы справиться с проблемой в Python пришлось отказаться от концепции, когда имена предварительно не объявляются, и разрешить в теле метода объявлять имена переменных как глобальные. Синтаксически, такое объявление выглядит так:
global <кортеж имен глобальных переменных модуля>
Если в теле функции дано такое объявление, то имена в кортеже воспринимаются как глобальные, что позволяет передавать им информацию.
Заметьте, имена в этом списке, могут предварительно не вводиться в модуле. Они появятся там в результате выполнения соответствующей функции. Приведу пример такого способа передачи данных от функции, использующий глобальные переменные модуля. Содержательно этот пример связан со следующей задачей. Когда-то школьники, с которыми я занимался, писали игру "Отгадай число", где компьютер задумывал число, выбирая его случайным образом из некоторого интервала. Сам интервал при каждом запуске игры менялся случайным образом, и его величина зависела от уровня игры. Наш пример моделирует фрагменты этой игры:
import random def MinMax(a): """ Процедура MinMax вычисляет максимальный и минимальный элементы - случайные границы интервала чисел и передает информацию через создаваемые глобальные переменные Min, Max """ global Min, Max Min = random.randint(0, a) Max = random.randint(Min + 1, 2 * a)
Вызов процедуры MinMax создаст на уровне модуля глобальные переменные, доступные в других функциях. Функция CreateNumber имеет параметр, задающий уровень игры, и использует глобальные переменные Min и Max при вычислении интервала для выбора случайного числа:
def CreateNumber(level): """ Функция возвращает случайное число в диапазоне, зависящем от глобальных переменных Min, Max и уровня игры - level """ if level == 1: return random.randint(Min, Max) if level == 2: return random.randint(Min * 20, Max * 20) if level > 2: return random.randint(Min * 40, Max * 40)
Построим соответствующий тест:
def test4(): print('уровень 1') MinMax(10) n = CreateNumber(1) print('число ', n, 'из интервала ', Min, ' - ', Max) print('уровень 2') MinMax(10) n = CreateNumber(2) print('число ', n, 'из интервала ', Min * 20, ' - ', Max * 20) print('уровень 4') MinMax(10) n = CreateNumber(4) print('число ', n, 'из интервала ', Min * 40, ' - ', Max * 40) test4()
Вот результаты работы:
Подводя промежуточные итоги, можно отметить, что имена, связываемые с объектами на уровне модуля, являются глобальными и видимы во всем модуле за исключением тех областей модуля, где действуют локальные переменные с тем же именем. Имена функций, объявленных в модуле, являются глобальными. Имена, связываемые с объектами, на уровне функции, являются локальными. Видимость глобальных имен в теле метода позволяет передать методу глобальную информацию, в частности использовать атрибуты метода. Но и метод, в свою очередь, может изменять глобальную информацию, в частности атрибуты метода, что позволяет методам обмениваться информацией через атрибуты метода.