Теория урока

69. Еще о возможностях модулей в Python

Оглавление урока

Введение

В предыдущем уроке мы познакомились с пакетами в Python, еще ранее научились писать модули. Осталось поговорить об оставшихся темах, которые не вошли в предыдущие уроки: переменная __name__, модуль __future__, сокрытие данных и другие.

Для начала рассмотрим основные принципы и идеи, связанные с модулями.

В Python любой код всегда находится внутри модуля, даже набираемый в интерактивной оболочке, на самом деле оказывается во встроенном модуле __main__.

Сведите к минимуму количество глобальный переменных. Про инкапсуляцию поговорим в теме по ООП.

Модули должны в редких случаях менять переменные других модулей. Использование глобальных переменных является частой практикой для передачи результатов между модулями. Зачастую такое решение следует из-за неправильного проектирования (за исключением некоторых случаев) и приводит к запутыванию кода и усложнению его дальнейшей поддержки. Лучше обмениваться данными между модулями при помощи аргументов функций и возвращаемых значений.

Сокрытие данных в модулях

Иногда нам необходимо ограничить доступ к некоторым данным извне модуля. В этом уроке «сокрытие данных» и «инкапсуляция» будем считать синонимами. Сразу приведу пример, а дальше разберемся:

Пример
'''  b.py  '''
a = 1
_b = 2

И основной файл:

Пример
'''  a.py  '''
from b import *

print(a)
print(_b)

В Python все имена модуля являются публичными, т.е. доступными за пределами модуля. Но, если имя начинается с нижнего подчеркивания (как переменная _b), то оно становится приватным, т.е. недоступным за пределами модуля. Попробуйте запустить вышеуказанный код и убедиться в этом.

Такой способ сделать имя приватным работает только с оператором from … *. Давайте перепишем пример с использованием обычного импортирования при помощи import.

Пример
'''  a.py  '''
import b

print(b.a)
print(b._b)

Как видите, переменная _b не такая уже и приватная на самом деле. Взглянем на другой (противоположный) способ: переменная __all__. Python сначала ищет в модуле переменную __all__, содержащую список с именами (независимо, есть ли перед ними подчеркивание) и делает их все публичными, т.е. оператор from … * копирует их в файл верхнего уровня, а все остальные имена становятся «приватными».

Пример
'''  b.py  '''
__all__= ['_b']
a = 1
_b = 2

Файл верхнего уровня:

Пример
'''  a.py  '''
from b import *

print(a)
print(_b)

При использовании обычного импортирования при помощи оператора import, мнимая приватность не работает.

Включение будущих средств языка: __future__

Изменение языка иногда может нарушить работу кода и поэтому в Python решили вводить такие изменения постепенно в виде необязательных расширений, которые выключены по умолчанию. Чтобы их включить, необходимо использовать оператор import следующего вида:

Пример
from __future__ import название

Переменная __name__ в Python

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

Пример
'''  a.py  '''

def print_x(x):
print(x)

def main():
print('Выполнение сценария началось')
print_x(10)

if __name__ == '__main__':
main()

Если вы программировали на С/С++, то «упаковка» кода внутрь функции main() вас не удивит. Запустите этот код и убедитесь в его очевидной работе. Он работает точно так же, как и этот:

Пример
'''  a.py  '''

def print_x(x):
print(x)

print('Выполнение сценария началось')
print_x(10)

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

Пример
'''  b.py  '''
import a

a.print_x(12)

Попробуйте запустить этот скрипт с двумя вариантами файла a.py по очереди. Когда файл a.py используется как модуль, переменная __name__ устанавливается в false и функция main() не выполняется. Как вы догадались, первый пример файла a.py можно было записать следующим образом:

Пример
'''  a.py  '''

def print_x(x):
print(x)

if __name__ == '__main__':
print('Выполнение сценария началось')
print_x(10)

Если вы забыли, как работают функции, то можете повторить раздел «Функции», начиная с урока «Основы функций в Python».

Аргументы командной строки

Если вы знакомы с С/С++, то вероятно знаете про аргументы командной строки:

Пример
int main(int argc, char* argv[]) { /* ... */ }

В Python тоже есть аргументы командной строки, но они не объявляются так явно в коде. Рассмотрим пример:

Пример
'''  a.py  '''
import sys

if __name__ == '__main__':
print(sys.argv)

Во-первых, следует подключить модуль sys. Этот модуль имеет список аргументов argv, в котором хранится первым элементом путь до запускаемого скрипта, а далее переданные через командную строку аргументы:

Пример
$ a.py 123 Слово

Скрипт a.py напечатает в консоли:

Пример
['a.py', '123', 'Слово']

Как перебирать списки вы научились в уроке «Списки в Python».

Изменение пути поиска модулей

В первом уроке по модулям «Модули в Python» мы говорили о возможности изменения путей поиска, но не показывали, как это сделать. Напомню, по итогу образуется список из путей, который хранится под именем path в модуле sys. Чтобы посмотреть список путей, в которых осуществляется поиск, можно просто вывести этот список:

Пример
'''  a.py  '''
import sys
print(sys.path)

Мы уже несколько раз сказали: «Это список». Этот список мы можем редактировать как нам вздумается: добавлять элементы, удалять их или полностью очистить список. О методах работы со списками мы говорили в уроке «Списки в Python». Например, добавим путь:

Пример
sys.path.append('c:\code')

Выполнение строк с кодом

Если вдруг вам необходимо импортировать модуль, название которого «создается» динамически, можете попробовать так:

Пример
import 'module_1'

И получить ошибку о неправильном синтаксисе. Хорошо. Попробуем обмануть и укажем динамически созданное название модуля в переменной:

Пример
x =  'module_1'
import x

Синтаксической ошибки не будет, но и модуль module_1 не будет подключен, так как интерпретатор будет искать с именем x. Переменная будет восприниматься как название модуля. Не расстраивайтесь, мы можем это обойти при помощи функции exec(), которая динамически выполняет большие блоки Python-кода.

Пример
x =  'module_1'
exec('import ' + x)

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

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

Пример
x =  'module_1'
__import__(x)

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

ПРОЧИТАНО
Следующий урок

Похожие уроки и записи блога

Обработка исключений (try/except) в PythonЗнакомство с Python
Написание модулей в PythonЗнакомство с Python
Продолжаем написание классов в PythonЗнакомство с Python
Первое знакомство с PythonЗнакомство с Python
Типы данных в PythonЗнакомство с Python
Модули в PythonЗнакомство с Python
Функциональное программирование: map, filter и reduceЗнакомство с Python
Работа с файлами в Python Знакомство с Python
Аргументы и параметры функций, операторы * и ** в PythonЗнакомство с Python
<
×
>
Впервые на сайте Codebra?

Извините за это всплывающее окно, меня они тоже раздражают.

Образовательный ресурс codebra.ru полностью посвящен программированию. Все курсы и уроки находятся на главной странице. Ради интереса можете посмотреть на содержимое курсов по Python, HTML и CSS, JavaScript, C++ и другие, размещенные на главной странице.

Если что-то не нашли, то воспользуйтесь поиском по сайту, который находится на главной странице в самом верху.

Удачи в обучении!

Закрыть окно