Python область видимости import

67. Написание модулей в Python

В предыдущем уроке мы начали знакомство с модулями. Хотя, как начали, продолжили более глубокое изучение, так как неоднократно с ними уже встречались.

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

Чтобы создать модуль в Python, откройте текстовый файл и напишите там какой-нибудь код на Python. После чего сохранить его с расширением .py . Имя модуля может быть практически любым. Например, нельзя назвать модуль if.py или использовать в имени другое зарезервированное слово, так как импортирование оператором import модуля с таким именем приведет к ошибке. Именование модулей и каталогов подчиняется правилам создания имен для переменных (если забыли, то вернитесь к уроку «Переменные и комментарии в Python»).

Использование модулей

Использовать только что написанный модуль можно сразу при помощи операторов import и from . С первым мы уже разобрались. Второй работает практически также, но в отличие от первого, который импортирует модуль как единое целое, оператор from извлекает только необходимые «функциональные части» модуля. Далее рассмотрим пример, файл a.py выглядит следующим образом:

Модуль b.py представлен ниже:

def hello(): 
print('Привет из модуля b.py')

Работа оператора import уже вам знакома из предыдущего урока. Теперь извлечем только часть из модуля – атрибут hello() .

Таким образом, мы применяем в сценарии скопированное имя hello() напрямую, не указывая на объект b , как в предыдущем примере. Оператор from работает так же, как и import (выполняет трехшаговую процедуру из предыдущего урока), добавляя один свой «шаг» — копирование одного или более имен из файла модуля. Чтобы импортировать несколько имен, необходимо их перечислить через запятую:

from b import hello, func1, func2

В Python есть другая форма оператора from , позволяющая скопировать все имена из модуля. По факту, так мы интегрируем пространство имен модуля в файл верхнего уровня:

Операторы from и import являются исполняемыми, а значит их можно помещать в условные конструкции if , внутрь функций, использовать в операторах try (урок про исключения «Обработка исключений (try/except) в Python») и так далее.

Имена, копируемые оператором from , становятся ссылками на соответствующие объекты. Про то, как происходит присваивание в Python, мы говорили, например, здесь: «Типы данных в Python». С модулями точно так же. Рассмотрим пример:

''' a.py '''
from b import *

print_x() # => 10
print_y() # => [1, 2]

x = 20
y[1] = 30

print_x() # => 10
print_y() # => [1, 30]
''' b.py '''
x = 10
y = [1, 2]

def print_x():
print(x)

def print_y():
print(y)

Как видите, мы присвоили в файле верхнего уровня объекту y , который ссылается на y из модуля, другое значение для элемента с индексом 1 (более подробно об этом было в разделе «Копирование списков» в уроке «Конкатенация и сортировка списков в Python»).

Читайте также:  Моем inurl index php

Оставим модуль b.py без изменений и подключим его при помощи оператора import .

''' a.py '''
import b

b.print_x() # => 10
b.print_y() # => [1, 2]

b.x = 20
b.y[1] = 30

b.print_x() # => 20
b.print_y() # => [1, 30]

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

Согласен, сложно это понять сходу, поэтому перепишем импортирование в предыдущем примере ( from b import * ) вот так:

import b
x = b.x
y = b.y
print_x = b.print_x
print_y = b.print_y
del b

Еще раз вернувшись к разделу «Модель данных» урока «Типы данных в Python» и прочитав, как работает операция присвоения в Python, у вас сложится более хорошее понимание отличия операторов import и from … * . Как видите, оператор from импортирует целый модуль, независимо от количества необходимых имен.

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

Еще про трудности, связанные с from и import

Оператор from делает переменные из модуля менее явными в коде (если вы читаете код, то проще понять его, когда написано имя.модуль , а не просто имя). Из-за этого некоторые энтузиасты рекомендуют использовать оператор import , вместо from . Лично я не считаю такой совет полезным, так как на практике удобней не набирать имя модуля каждый раз при использовании его инструментов, особенно это касается больших модулей.

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

Читайте также:  Format time from datetime php

Так же оператор from может добавить проблем в совокупности с функцией reload .

Выбор за вами. Рекомендую отдавать предпочтение оператору import перед from для простых модулей, а также для последнего явно перечислять требуемые переменные через запятую и не злоупотреблять второй формой оператора from … * . А вот в случае необходимости использования одного и того же имени из разных модулей, оператор import обязателен, так как from здесь уже точно не подойдет.

Пространства имен модулей

В предыдущем уроке мы определили: модуль – изолированное хранилище для имен, а имена в модуле называются атрибутами. Как происходит «создание» пространства имен. Все имена на верхнем уровне файла становятся его атрибутами (переменные внутри тела функции или класса таковыми не являются).

Доступ к пространству имен модуля можно получить при помощи функции dir() :

''' a.py '''
import b
print(dir(b))
Или атрибут __dict__:

''' a.py '''
import b
print(b.__dict__) # b.__dict__.keys() для вывода только ключей

Как вы поняли, пространство имен модуля хранится как объект словаря:

»’ a.py »’
import b
print(b.__dict__[‘print_x’]) # =>

Это обычные словари, с которыми вы научились работать, начиная с урока «Словари в Python».

Область видимости и импортирование

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

Перезагрузка модулей

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

''' a.py '''
import b
print(b.y) # => [1, 2]

b.y[1] = 20
print(b.y) # => [1, 20]

from importlib import reload

reload(b)
print(b.y) # => [1, 2]

Обратите внимание, функцию reload() необходимо импортировать из библиотеки importlib для Python 3.4 и выше. В ранних версиях эта функция находилась в модуле imp , а версии Python 2 была встроенной.

Читайте также:  Алгоритм гаусса ньютона python

Наш урок подошел к концу. В нем мы рассмотрели важные особенности написания модулей в Python, познакомились с операторами import и from , а также функцией reload() . Разобрались с пространствами имен и уяснили, когда импортировать при помощи оператора import , а когда при помощи оператора from .

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

Источник

Покоряем Python — уроки для начинающих

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

Например, рассмотрим два следующих простых модуля. Первый, в файле moda.py ,
определяет переменную X , которая является глобальной только для программного кода в этом файле, и функцию, изменяющую глобальную переменную X
в этом файле:
X = 88 # Переменная X: глобальная только для этого файла
def f():
global X # Изменяет переменную X в этом файле
X = 99 # Имена в других модулях недоступны
Второй модуль, modb.py, определяет свою собственную глобальную перемен-
ную X, а также импортирует и вызывает функцию из первого модуля:
X = 11 # Переменная X: глобальная только для этого файла

import moda # Получает доступ к именам в модуле moda
moda.f() # Изменяет переменную moda.X, но не X в этом файле
print X, moda.X

При запуске этого модуля функция moda.f изменит переменную X в модуле moda , а не в modb . Глобальной областью видимости для функции moda.f всегда является файл, вмещающий ее, независимо от того, из какого модуля она была вызвана:
% python modb.py
11 99
Другими словами, операция импортирования никогда не изменяет область видимости для программного кода в импортируемом файле – из импортируемого файла нельзя получить доступ к именам в импортирующем файле. Если быть более точным:

  • Функциям никогда не будут доступны имена, определенные в других функциях, если только они физически не вложены друг в друга.
  • Программному коду модуля никогда не будут доступны имена, определенные в других модулях, если только они явно не были импортированы.

Источник

Оцените статью