0 знаков
60. Еще о возможностях модулей в Python
Кратко- В Python любой код всегда находится внутри модуля.
- Сведите к минимуму количество глобальных переменных.
- Модули должны в редких случаях менять переменные других модулей.
- Лучше обмениваться данными между модулями при помощи аргументов функций и возвращаемых значений.
- Сокрытие данных в модулях: использование нижнего подчеркивания для приватных переменных.
- Включение будущих средств языка: оператор
importс необязательными расширениями.- Переменная
__name__в Python: используется для определения, является ли файл модулем или сценарием.- Аргументы командной строки в Python: модуль
sysдля работы с ними.- Изменение пути поиска модулей в Python: использование функции
exec()для динамического выполнения кода.
Введение
В предыдущем уроке мы познакомились с пакетами в 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__, которая позволяет использовать файл верхнего уровня в роли модуля и попробовали передать аргументы в сценарий из командной строки. В конце урока научились выполнять строки с кодом и подключать модули с динамическим именем. В следующем уроке подведем итоги раздела и затем перейдем к ООП.
Тест
Похожие уроки Codebra
Подписывайся на наш Telegram-канал!
Новости, полезный материал,
программирование и ИБ
Подписывайся на наш Telegram-канал!
Новости, полезный материал,
программирование и ИБ