НОЧУ ДПО "Национальный открытый университет "ИНТУИТ"
Опубликован: 24.01.2021 | Доступ: свободный | Студентов: 2489 / 106 | Длительность: 03:57:00
Лекция 18:

Модульное программирование: атрибуты и методы

< Лекция 1 || Лекция 18: 12

Смотреть на 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()

Вот результаты работы:


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

< Лекция 1 || Лекция 18: 12
Алексей Авилов
Алексей Авилов

Неужели не нашлось русских специалистов, чтобы записать курс по пайтону ? Да, можно включить переводчик и слушать с переводом, но это что? Это кто-то считает хорошим и понятным курсом для начинающих? 

Елена Лаптева
Елена Лаптева

Думаю. что не смогу его закончить. Хотелось предупредить других - не тратьте зря время, ищите другой курс.