Области видимости¶
Эти записи я делаю по ходу самообучения. Пока во всех источниках прослеживается глобальая методическая ошибка. Вместо того, чтобы на простом примере (кода) определить основные понятия, авторы заставляют меня ломать голову на тем, что такое "области видимости объемлющих функции".
Это любимые грабли многих естественников. Т.н. классическое изложение - сначала теория, потом примеры... Сначала должны идти разъяснения используемых в "теории" понятий...
Кроме того, никто не борется с неизбежностью затрат времени на усвоение понятий... Это все равно, что одноверменно учить язык Хинди и слушать лекции на нем...
А еще и переводчики малограмотные попадаются...
Потому постараюсь здесь (как Пастер и Павлов) записать и те вопросы, которые у меня возникают в процессе чтения классических учебников...
Сначала я намеревался поместить здесь мой конспект главы 16 из книги М.Лутца "Изучаем Питон" (2011 pdf)
...имена появляются в тот момент, когда им впервые присваиваются некоторые значения, и прежде чем имена смогут быть использованы, им необходимо присвоить значения. Поскольку имена не объявляются заранее, интерпретатор Python по местоположению операции присваивания связывает имя с конкретным пространством имен.
Как мы узнаем далее в этой главе, значения переменным могут быть присвоены в трех разных
местах, соответствующих трем разным областям видимости:• Если присваивание переменной выполняется внутри инструкции def, переменная является локальной для этой функции.
• Если присваивание производится в пределах объемлющей инструкции def, переменная является нелокальной для этой функции.
• Если присваивание производится за пределами всех инструкций def, она является глобальной для всего файла. Однако там все слишком подробно, точнее, так много слов, что не понимаешь, что надо запомнить... тем не менее, будем и дальше цитировать эту книгу (с таким же форматированием цитат), но и другие источники нам понадобятся.
Вот, онлайн ресурс Учебник Python 2.6 мне понравился ... и я его поместил во фрейм внизу.
In [1]:
from IPython.display import HTML
In [2]:
HTML('<iframe src=http://ru.wikibooks.org/wiki/%D0%A3%D1%87%D0%B5%D0%B1%D0%BD%D0%B8%D0%BA_Python_2.6#.D0.9E.D0.B1.D0.BB.D0.B0.D1.81.D1.82.D0.B8_.D0.B2.D0.B8.D0.B4.D0.B8.D0.BC.D0.BE.D1.81.D1.82.D0.B8_.D0.B8_.D0.BF.D1.80.D0.BE.D1.81.D1.82.D1.80.D0.B0.D0.BD.D1.81.D1.82.D0.B2.D0.B0_.D0.B8.D0.BC.D1.91.D0.BD_.D0.B2_Python width=800 height=350></iframe>')
Out[2]:
Несмотря на то, что области видимости определяются статически, используются они динамически. В любой момент во время выполнения существует как минимум три вложенных области видимости, чьи пространства имён доступны прямым образом:
самая глубокая[55] область видимости, по которой поиск осуществляется в первую очередь, содержит локальные имена; пространства имён всех заключающих [данный код] функций, поиск по которым осуществляется начиная с ближайшей заключающей [код] области видимости;
область видимости среднего уровня, по ней следующей проходит поиск и она содержит глобальные имена текущего модуля;
и самая внешняя область видимости (заключительный поиск) — это пространство имён, содержащее встроенные имена.
In [3]:
from IPython.display import Image
Image(filename='C:\\Users\\kiss\\Pictures\\for_blogs\\py_vis.png')
Out[3]:
в локальной области видимости,
во всех локальных областях видимости объемлющих функций,
в глобальной области видимости и,
наконец, во встроенной области видимости.
Поиск завершается, как только будет найдено первое подходящее имя. Место, где в программном коде производится присваивание значения переменной, обычно определяет ее область видимости Ну что же, будем надеяться, что (дурацкий) перевод enclosure - объемлющие функции дальше станет понятным. Ага, нашел (Лутц стр 487)
In [5]:
X = 99 # Имя в глобальной области видимости: не используется
def f1():
X = 88 # Локальное имя в объемлющей функции
def f2():
print(X) # Обращение к переменной во вложенной функции
f2()
f1() # Выведет 88: локальная переменная в объемлющей функции
In [8]:
X = 99 # Имя в глобальной области видимости: не используется
def f1():
# X = 88 # если нет Локального имени, то поиск "всплывает"
def f2():
print(X) # Обращение к переменной во вложенной функции
f2()
f1() # Выведет 88: локальная переменная в объемлющей функции
инструкция def – это обычная исполняемая инструкция, которая может появляться в любом месте программы...
... В некотором смысле f2 – это временная функция, которая существует только во время работы (и видима только для программного кода) объемлющей функции f1
In [7]:
def f1():
X = 88
def f2():
print(X) # Сохраняет значение X в объемлющей области видимости
return f2 # Возвращает f2, но не вызывает ее
action = f1() # Создает и возвращает функцию
action() # Вызов этой функции: выведет 88
Например, IDLE запускает ваши сценарии в своем окружении, поэтому переменные, определяемые сценарием, автоматически становятся доступны в интерактивном сеансе IDLE – вам не придется запускать команду import, чтобы получить доступ к именам в файлах верхнего уровня, которые уже были запущены. Это может быть удобно, но может вызывать проблемы при работе вне среды IDLE, потому что в этом случае всегда необходимо импортировать имена из используемых файлов. Кроме того, неплохо было бы уточнить, как трактовать видимость в классах ... и как сопряжено с видимостью соглашение "self"? Ответ находим у Лутца (стр. 698) Найти первое вхождение атрибута attribute, просмотрев объект object, а потом все классы в дереве наследования выше него, снизу вверх и слева направо
In [9]:
Image(filename='C:\\Users\\kiss\\Pictures\\for_blogs\\py_c_tree.PNG')
Out[9]:
Каждый из этих объектов обладает набором атрибутов. Если говорить более точно, это дерево связывает вместе три объекта классов (в овалах, C1, C2 и C3) и два объекта экземпляров (в прямоугольниках, I1 и I2) в иерархию наследования.
Обратите внимание, что в модели объектов в языке Python классы и экземпляры порождаются от двух разных типов объектов: Классы
Играют роль фабрик экземпляров. Их атрибуты обеспечивают поведение – данные и функции – то есть наследуются всеми экземплярами, созданными от них (например, функция, вычисляющая зарплату служащего, исходя из часового тарифа). Экземпляры
Представляют конкретные элементы программы. Их атрибуты хранят данные, которые могут отличаться в конкретных объектах (например, номер карточки социального страхования служащего). ...из-за того, что поиск производится снизу верх, подклассы могут переопределять поведение, определяемое их суперклассами, переопределяя имена суперклассов ниже в дереве. Т.к. эти последние несколько слов отражают основную суть адаптации программного обеспечения в ООП, давайте подробнее рассмотрим эту концепцию. Предположим, что мы создали дерево, приведенное на рис. 25.1, и затем пишем: I2.w Этот программный код демонстрирует использование механизма наследования. Так как это выражение вида object.attribute, оно приводит к запуску поиска в дереве, изображенном на последнем рисунке, – интерпретатор приступает к поиску атрибута w, начиная с I2, и движется вверх по дереву. В частности, он будет просматривать объекты в следующем порядке: I2, C1, C2, C3 и остановится, как только будет найден первый атрибут с таким именем (или возбудит исключение, если атрибут w вообще не будет найден). В этом случае поиск будет продолжаться, пока не будет достигнут объект C3, поскольку атрибут w имеется только в этом объекте. Другими словами, имя I2.w в терминах автоматического поиска будет обнаружено, как C3.w. В терминологии ООП это называется I2 «наследует» атрибут w от C3.
Комментариев нет:
Отправить комментарий