Искать
Вы превысили запрос на
0 знаков

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

Не пройден
0
0

Кратко

- В Python любой код всегда находится внутри модуля.

- Сведите к минимуму количество глобальных переменных.

- Модули должны в редких случаях менять переменные других модулей.

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

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

- Включение будущих средств языка: оператор import с необязательными расширениями.

- Переменная __name__ в Python: используется для определения, является ли файл модулем или сценарием.

- Аргументы командной строки в Python: модуль sys для работы с ними.

- Изменение пути поиска модулей в Python: использование функции exec() для динамического выполнения кода.

Введение

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

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

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

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

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

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

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

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

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

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

print(a)
print(_b) 

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

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

Пример (python)
'''  a.py  '''
import b

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

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

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

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

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

print(a)
print(_b) 

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

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

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

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

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

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

Пример (python)
'''  a.py  '''

def print_x(x):
    print(x)

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

if __name__ == '__main__':
    main() 

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

Пример (python)
'''  a.py  '''

def print_x(x):
    print(x)

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

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

Пример (python)
'''  b.py  '''
import a

a.print_x(12) 

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

Пример (python)
'''  a.py  '''

def print_x(x):
    print(x)

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

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

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

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

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

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

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

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

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

Пример (bash)
a.py 123 Слово 

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

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

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

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

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

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

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

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

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

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

Пример (python)
import 'module_1' 

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

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

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

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

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

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

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

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

Тест

Две секундочки...

Похожие уроки Codebra

@codebra_official
Подписывайся на наш Telegram-канал!
Новости, полезный материал,
программирование и ИБ
Обработка исключений (try/except) в PythonЗнакомство с Python
Продолжаем написание классов в PythonЗнакомство с Python
Пользовательские функции в PHPКурс по PHP
Написание модулей в PythonЗнакомство с Python
Типы данных в PythonЗнакомство с Python
Поиск хостов с помощью NmapРазведка и сканирование
Первое знакомство с PythonЗнакомство с Python
Работа с файлами в PythonЗнакомство с Python
Переменные, комментарии и типы данных в PHPКурс по PHP
Впервые на сайте Codebra?

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

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

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

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

Закрыть окно