Импорт и создание модулей
Питон включает в себя обширную библиотеку модулей, в которых реализовано множество полезных функций. Далее в этом курсе мы будем применять и другие полезные модули: re для регулярных выражений, collections , содержащий множество удобных структур данных, os и shutil для управления файлами и папками.
Для использования модуля его нужно импортировать — попросить питон загрузить его и сделать его функции доступными для использования. Импорт осуществляется с помощью оператора import . Например, модуль random используется для генерации “случайных” чисел.
>>> import random >>> # Теперь мы можем вызывать функции из модуля random, указав их имя после "random." с точкой >>> random.randint(0, 5) # выводит случайное целое число между 0 и 5 включительно 2 >>> random.choice('abcdef') # выберает случайный элемент коллекции 'c' >>> random.random() # Выводит случайное число на полуинтервале [0, 1) 0.9131300358342321
Ещё один пример: модуль math , содержащий различные математические функции и константы
>>> math.cos(0) # ошибка, модуль ещё не импортирован --------------------------------------------------------------------------- NameError Traceback (most recent call last) ipython-input-4-9cdcc157d079> in module>() ----> 1 math.cos(0) NameError: name 'math' is not defined >>> import math >>> math.cos(0) 1.0 >>> math.asin(1) 1.5707963267948966 >>> math.e 2.718281828459045
Использование псевдонимов
Если название модуля слишком длинное и вы не хотите его писать каждый раз, когда используете какую-то функцию, вы можете импортировать этот модуль под псевдонимом с помощью as:
>>> import math as m >>> m.factorial(5) 120
Импорт нескольких модулей
Модули можно импортировать в одну строчку через запятую, если требуется использовать несколько, либо можно писать каждый импорт на новой строчке.
>>> import random, math >>> math.sqrt(random.randint(0, 5)) 2.23606797749979
import random import math
>>> math.sqrt(random.randint(0, 5)) 2.0
Инструкция from
Иногда в модуле бывает много разных функций, а вам нужно использовать только что-то одно (и, например, использовать много раз), тогда проще импортировать какую-то определенную функцию из этого модуля и (1) чуть-чуть сэкономить память, (2) короче синтаксис. Тогда синтаксис импорта будет следующий:
>>> from math import ceil, floor >>> ceil(145.3) 146 >>> floor(145.6) 145
Также можно импортировать из модуля всё. То есть все функции, переменные и классы. Тогда нам не нужно каждый раз писать название модуля.
>>> from math import * >>> sqrt(144) 12.0 >>> pi 3.141592653589793
Однако, это очень плохая практика так как в двух разных модулях могут быть одинаковые функции и при импорте вы просто не будете знать, какую используете.
Правило хорошего тона — импортировать модули вначале вашей программы, до любого другого кода и функций.
Создание своего модуля питон
Любой файл с исходным кодом на Python — модуль! Это значит, что любая программа может выступать в роли модуля для другой и импортироваться.
Давайте напишем скрипт с парой функций и импортируем эти функции в другую программу.
Создадим программу mymodule.py:
def avg(numbers): if not numbers: return 0 return sum(numbers) / len(numbers) def myfactorial(n): if n == 1: return n elif n 1: return ("NA") else: return n * myfactorial(n-1)
В ней мы прописали две математические функции: среднее и факториал. Предположим теперь мы хотим воспользоваться ими в какой-нибудь другой программе myscript.py. Тогда мы положим эти два файла в одну директорию, чтобы импорт работал. И в результате мы сможем ипмортировать эти функции в новую программу.
Файл myscript.py:
import mymodule n = input("Введите число: ") my_list = [1] * (int(n)/2) + [2] * (int(n)/2) print(mymodule.avg(my_list)) print(mymodule.myfactorial(int(n)))
Кстати, найдите баг в этом коде:
>>> [1] * (5/2) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) ipython-input-35-f37e9b720bb2> in module> ----> 1 [1] * (5/2) TypeError: can't multiply sequence by non-int of type 'float' >>> [1] * (5//2) [1, 1]
Задача: составление анаграмм
В качестве примера использования функций и модуля стандартной библиотеки random рассмотрим задачу составления анаграмм. В качестве входного файла будем использовать любой текст, из которого мы выберем слова. Пусть текст находится в файле text.txt и имеет следующее содержание (из Яндекс.Рефератов):
Субъект вызывает мелодический импульс. Пласт параллельно понимает понимающий эриксоновский гипноз, следовательно тенденция к конформизму связана с менее низким интеллектом. Дифференциация, по определению, дает звукорядный бихевиоризм.
Задача состоит в том, что необходимо составить файл формата TSV, состоящий из 4 колонок: слово из файла и три его случайных анаграммы. Для простоты анаграммы могут совпадать с самим словом или друг с другом. В итоге требуется получить файл table.tsv , который будет начинаться следующим образом:
субъект ъсукебт кутесъб кеубътс вызывает езтавыыв аыезыввт ывеаывзт мелодический скйчмеелидио диимечеслйок мкееийлчосид импульс млсупьи уьмипсл льмпиус пласт сатпл таслп тпалс .
Полный код для решения этой задачи может выглядеть следующим образом:
"""Эта программа собирает слова из text.txt и составляет список анаграмм из них в таблице table.tsv""" # Здесь мы импортируем модуль стандартной библиотеки random, в котором # содержаться функции для работы с псевдослучайными числами. # Правило хорошего тона — делать все импорты в начале вашей программы. import random def words_from_file(filename): """Принимает имя файла, а точнее его системный путь, и возвращает список слов в нем """ with open(filename, encoding='utf-8') as f: # открвываем файл text = f.read() # прочитываем весь файл в строковую переменную text = text.replace('-', '') # удаляем дефисы text = text.replace(',', '').replace('.', '') # удаляем запятые и точки # Тут можно было почистить текст еще лучше text = text.lower() # заменяем все заглавные на строчные words = text.split() # получаем список слов return words # возвращаем список слов def anа(word): """Возвращает случайную анаграмму word""" # Функция random.sample(sequence, count) возвращает список из count # уникальных элементов последовательности (например списка или строки) # взятых в случайном порядке. Заметим, что каждый элемент не может быть # больше одного раза, а также напомним, что элементами строки являются # односимвольные строки. a = random.sample(word, len(word)) # получаем список перемешанных букв new_word = ''.join(a) # объединяем элементы списка из букв в одну строку return new_word # возвращаем анаграмму def create_tsv_table(table_filename, words, n_anа): """Создает TSV-файл с именем table_filename со строками типа слово→анаграмма→анаграмма. где список слов задается аргументом words, а число анаграмм — n_ana """ with open(table_filename, 'w', encoding='utf-8') as f: # открываем файл для записи for x in words: # перебираем слова в переменной x f.write(x) # запишем слово в файл for i in range(n_ana): # n_ana раз создадим и запишем анаграмму f.write('\t') # запишем разделитель f.write(ana(x)) # запишем случайную анаграмму f.write('\n') # не забудем поставить символ конца строки перед следующей строкой def main(): words = words_from_file('text.txt') # получаем список слов create_tsv_table('table.tsv', words, 3) # создаем таблицу с тремя анаграммами в каждой строке if __name__ == '__main__': main()
Домашнее задание
Пусть какая-то функция получает на вход список из 30 случайных целых чисел от 0 до 100, сгенерированных с помощью модуля random. В вариантах описана функция.
+1 балл для всех: ответьте коротко на вопрос “Почему модуль random на самом деле НЕ генерирует случайные числа?”
- Функция берёт два случайных числа из этого списка (с помощью модуля random) и считает по ним количество всевозможных сочетаний этих чисел с точки зрения теории вероятности, С из n по k (использовать функцию из модуля math – factorial). Количество сочетаний (в формате float) печатается. k должно быть меньше n
- Функция возвращает произведение значений списка. Нужно пользоваться модулем math. Руководствоваться надо тем, что exp(log(a) + log(b)) = a * b
- Функция возвращает строку из 30 букв. Список, полученный на вход, задает порядок букв в строке по номеру буквы в алфавите.
- Функция берёт из списка 4 случайных числа, условно принимает их за две точки в двумерном пространстве и возвращает евклидово расстояние между этими точками. Использовать модули random и math.
- Функция перемешивает список с помощью random.shuffle(), сравнивает его с исходным списком и возвращает количество индексов, значение элемента по которым поменялось. Запустите функцию в цикле 100 раз и напечатайте в скольки процентов случаев меняются все элементы списка.
- Функция возвращает среднее геометрическое списка. Вомпользуйтесь модулем math. Отдельно вне функции покажите, что ее результат лежит между минимальным и максимальным значениями списка для 20 случаев. (Для это нужно на каждой итерации генерировать подаваемый на вход список заново)
- Функция возвращает среднее арифметическое элементов списка, округлённое вверх. Используйте модуль math.
Работа с модулями: создание, подключение инструкциями import и from

Модулем в Python называется любой файл с программой (да-да, все те программы, которые вы писали, можно назвать модулями). В этой статье мы поговорим о том, как создать модуль, и как подключить модуль, из стандартной библиотеки или написанный вами.
Каждая программа может импортировать модуль и получить доступ к его классам, функциям и объектам. Нужно заметить, что модуль может быть написан не только на Python, а например, на C или C++.
Подключение модуля из стандартной библиотеки
Подключить модуль можно с помощью инструкции import. К примеру, подключим модуль os для получения текущей директории:
import указывается название модуля. Одной инструкцией можно подключить несколько модулей, хотя этого не рекомендуется делать, так как это снижает читаемость кода. Импортируем модули time и random.
Использование псевдонимов
Если название модуля слишком длинное, или оно вам не нравится по каким-то другим причинам, то для него можно создать псевдоним, с помощью ключевого слова as.
Инструкция from
Подключить определенные атрибуты модуля можно с помощью инструкции from. Она имеет несколько форматов:
Первый формат позволяет подключить из модуля только указанные вами атрибуты. Для длинных имен также можно назначить псевдоним, указав его после ключевого слова as.
Следует заметить, что не все атрибуты будут импортированы. Если в модуле определена переменная __all__ (список атрибутов, которые могут быть подключены), то будут подключены только атрибуты из этого списка. Если переменная __all__ не определена, то будут подключены все атрибуты, не начинающиеся с нижнего подчёркивания. Кроме того, необходимо учитывать, что импортирование всех атрибутов из модуля может нарушить пространство имен главной программы, так как переменные, имеющие одинаковые имена, будут перезаписаны.
Создание своего модуля на Python
Теперь пришло время создать свой модуль. Создадим файл mymodule.py, в которой определим какие-нибудь функции:
Теперь в этой же папке создадим другой файл, например, main.py:
Выведет:
Поздравляю! Вы сделали свой модуль! Напоследок отвечу ещё на пару вопросов, связанных с созданием модулей:
Как назвать модуль?
Помните, что вы (или другие люди) будут его импортировать и использовать в качестве переменной. Модуль нельзя именовать также, как и ключевое слово (их список можно посмотреть тут). Также имена модулей нельзя начинать с цифры. И не стоит называть модуль также, как какую-либо из встроенных функций. То есть, конечно, можно, но это создаст большие неудобства при его последующем использовании.
Куда поместить модуль?
Туда, где его потом можно будет найти. Пути поиска модулей указаны в переменной sys.path. В него включены текущая директория (то есть модуль можно оставить в папке с основной программой), а также директории, в которых установлен python. Кроме того, переменную sys.path можно изменять вручную, что позволяет положить модуль в любое удобное для вас место (главное, не забыть в главной программе модифицировать sys.path).
Можно ли использовать модуль как самостоятельную программу?
Можно. Однако надо помнить, что при импортировании модуля его код выполняется полностью, то есть, если программа что-то печатает, то при её импортировании это будет напечатано. Этого можно избежать, если проверять, запущен ли скрипт как программа, или импортирован. Это можно сделать с помощью переменной __name__, которая определена в любой программе, и равна "__main__", если скрипт запущен в качестве главной программы, и имя, если он импортирован. Например, mymodule.py может выглядеть вот так:
Для вставки кода на Python в комментарий заключайте его в теги
Python import, как и для чего?
В языке программирования Python подключение пакетов и модулей осуществляется с помощью import. Это позволяет распределять код по логическим "узлам" приложения(модели данных, обработчики, и тп.), что позволяет получить менее нагруженные кодом файлы.
- Повышается читаемость кода.
- Код логически разбит по "узлам", его поиск и дальнейший отлов ошибок становится понятнее и проще.
- Для разработки в команде это дает более четкое понимание, что и где делает каждый при выполнении "задания".
- Нужно понимать, что делается и для чего.
Как использовать import?
Синтаксис import в Python достаточно прост и интуитивно понятен:
# В данной строке импортируется something_we_want import something_we_want # В данной строке импортируется something_we_want, как aww(логично и просто) import something_we_want as aww # В данной строке импортируется из something_we_want something(логично и просто) from something_we_want import something # В данной строке импортируется из something_we_want something, как s(логично и просто) from something_we_want import something as s # Синтаксис as позволяет обращаться к импортируемому по новому нами описанному # далее имени(это работает только в рамках нашего файла)
Что можно импортировать?
Для более глубокого понимания import стоит рассмотреть пример, представленный ниже.
def something(): pass somedata = 5
# 1 случай import something_we_want something_we_want.something() import something_we_want print(something_we_want.somedata) # 2 случай import something_we_want as aww aww.something() import something_we_want as aww print(aww.somedata) # 3 случай from something_we_want import something something() from something_we_want import somedata print(somedata) # 4 случай from something_we_want import something as s s() from something_we_want import somedata as sd print(sd) # Классы импортируются по аналогии с функциями
Красиво, читаемо и понятно.
В чем же подвох?
Но даже в таком простом примере есть подвох, о котором многие не догадываются(если вы начинающий программист, то лучше перейдите к следующему оглавлению).
Идеология Python достаточно интересна, что позволяет ему иметь низкий порог вхождения, низкое время написания кода, высокую читаемость, но именно в ней и кроется подвох.
По своему опыту использования данного языка, сложилось отчетливое ощущение главной идеи ООП(все есть объект). Что же в этом плохого?
Все файлы, функции и тд. это объект. Но что это за объект и класс стоят за файлами(модулями)?
Все просто, это любимый всеми программистами класс, использующий паттерн проектирования Singleton.
Поэтому при достаточно ветвистой структуре, импорт переменной и дальнейшая ее модификация может порождать достаточно не простые в понимании баги(переменная в своем цикле жизни может иметь любое значение и никаких гарантий нет).
Ветвистая структура приложения и существующие подходы импортирования
Часто в разработке приложений программисты пытаются разбить программу по логическим "узлам". Данный подход повышает читаемость и позволяет вести разработку в команде(один человек занимается реализацией одного "узла", второй другого). Так порождается структура приложения, которая зачастую виду сложности функционала является достаточно обширной(ветвистой, потому что имея одну точку входа откуда уже обрастая функционалом это становится похожим на дерево).
Пример ветвистой структуры:
Существует 2 подхода импортирования(лучше выбрать один и придерживаться его весь проект):
- Именованный(абсолютный)
- Неименованный(относительный)
Пример именованного импорта из models.py в auth.py:
# auth.py from app.models import User
Пример неименованного импорта из models.py в auth.py:
# auth.py from ..models import User # Количество точек указывает на сколько (обьектов) мы поднимаемся от исходного. # В данном примере первая точка поднимает нас на уровень обьекта handlers, # А вторая точка поднимает нас на уровень обьекта app
Это два абсолютно разных подхода. В первом случае мы "идем" из "корня"(входной точки нашего приложения). Во втором случае мы "идем" от "листа"(нашего файла).
Плюсы и минусы подходов импорта:
Как работают импорты в Python
Импорты не так просты, как кажется. Тем более если они пишутся для двух несовместимых версий языка. Разбираемся с основными проблемами и их решением.

Порой бывает трудно правильно реализовать import с первого раза, особенно если мы хотим добиться правильной работы на плохо совместимых между собой версиях Python 2 и Python 3. Попытаемся разобраться, что из себя представляют импорты в Python и как написать решение, которое подойдёт под обе версии языка.
Ключевые моменты
- Выражения import производят поиск по списку путей в sys.path .
- sys.path всегда включает в себя путь скрипта, запущенного из командной строки, и не зависит от текущей рабочей директории.
- Импортирование пакета по сути равноценно импортированию __init__.py этого пакета.
Основные определения
- Модуль: любой файл *.py . Имя модуля — имя этого файла.
- Встроенный модуль: «модуль», который был написан на Си, скомпилирован и встроен в интерпретатор Python, и потому не имеет файла *.py .
- Пакет: любая папка, которая содержит файл __init__.py . Имя пакета — имя папки.С версии Python 3.3 любая папка (даже без __init__.py) считается пакетом.
- Объект: в Python почти всё является объектом — функции, классы, переменные и т. д.
Пример структуры директорий
test/ # Корневая папка packA/ # Пакет packA subA/ # Подпакет subA __init__.py sa1.py sa2.py __init__.py a1.py a2.py packB/ # Пакет packB (неявный пакет пространства имён) b1.py b2.py math.py random.py other.py start.py
Обратите внимание, что в корневой папке test/ нет файла __init__.py .
Что делает import
При импорте модуля Python выполняет весь код в нём. При импорте пакета Python выполняет код в файле пакета __init__.py , если такой имеется. Все объекты, определённые в модуле или __init__.py , становятся доступны импортирующему.
Основы import и sys.path
Вот как оператор import производит поиск нужного модуля или пакета согласно документации Python:
При импорте модуля
spam
интерпретатор сначала ищёт встроенный модуль с таким именем. Если такого модуля нет, то идёт поиск файла spam.py
в списке директорий, определённых в переменной sys.path .
sys.path инициализируется из следующих мест:
- директории, содержащей исходный скрипт (или текущей директории, если файл не указан);
- директории по умолчанию, которая зависит от дистрибутива Python;
- PYTHONPATH (список имён директорий; имеет синтаксис, аналогичный переменной окружения PATH ).
Программы могут изменять переменную sys.path
после её инициализации. Директория, содержащая запускаемый скрипт, помещается в начало поиска перед путём к стандартной библиотеке. Это значит, что скрипты в этой директории будут импортированы вместо модулей с такими же именами в стандартной библиотеке.
Технически документация не совсем полна. Интерпретатор будет искать не только файл (модуль) spam.py , но и папку (пакет) spam .
Обратите внимание, что Python сначала производит поиск среди встроенных модулей — тех, которые встроены непосредственно в интерпретатор. Список встроенных модулей зависит от дистрибутива Python, а найти этот список можно в sys.builtin_module_names (Python 2 и Python 3). Обычно в дистрибутивах есть модули sys (всегда включён в дистрибутив), math , itertools , time и прочие.
В отличие от встроенных модулей, которые при поиске проверяются первыми, остальные (не встроенные) модули стандартной библиотеки проверяются после директории запущенного скрипта. Это приводит к сбивающему с толку поведению: возможно «заменить» некоторые, но не все модули стандартной библиотеки. Допустим, модуль math является встроенным модулем, а random — нет. Таким образом, import math в start.py импортирует модуль из стандартной библиотеки, а не наш файл math.py из той же директории. В то же время, import random в start.py импортирует наш файл random.py .
Кроме того, импорты в Python регистрозависимы: import Spam и import spam — разные вещи.
Функцию pkgutil.iter_modules() (Python 2 и Python 3) можно использовать, чтобы получить список всех модулей, которые можно импортировать из заданного пути:
import pkgutil search_path = ['.'] # Используйте None, чтобы увидеть все модули, импортируемые из sys.path all_modules = [x[1] for x in pkgutil.iter_modules(path=search_path)] print(all_modules)
Чуть подробнее о sys.path
Чтобы увидеть содержимое sys.path , запустите этот код:
import sys print(sys.path)
Документация Python описывает sys.path так:
Список строк, указывающих пути для поиска модулей. Инициализируется из переменной окружения PYTHONPATH и директории по умолчанию, которая зависит от дистрибутива Python.При запуске программы после инициализации первым элементом этого списка, path[0], будет директория, содержащая скрипт, который был использован для вызова интерпретатора Python. Если директория скрипта недоступна (например, если интерпретатор был вызван в интерактивном режиме или скрипт считывается из стандартного ввода), то path[0] является пустой строкой. Из-за этого Python сначала ищет модули в текущей директории. Обратите внимание, что директория скрипта вставляется перед путями, взятыми из PYTHONPATH.Источник: Python 2 и Python 3
Документация к интерфейсу командной строки Python добавляет информацию о запуске скриптов из командной строки. В частности, при запуске python .py .
Если имя скрипта ссылается непосредственно на Python-файл, то директория, содержащая этот файл, добавляется в начало sys.path, а файл выполняется как модуль main.Источник: Python 2 и Python 3
Итак, повторим порядок, согласно которому Python ищет импортируемые модули:
- Модули стандартной библиотеки (например, math , os ).
- Модули или пакеты, указанные в sys.path :Если интерпретатор Python запущен в интерактивном режиме:sys.path[0] — пустая строка ''. Это значит, что Python будет искать в текущей рабочей директории, из которой вы запустили интерпретатор. В Unix-системах эту директорию можно узнать с помощью команды pwd.Если мы запускаем скрипт командой python
Обратите внимание, что при запуске скрипта для sys.path важна не директория, в которой вы находитесь, а путь к самому скрипту. Например, если в командной строке мы находимся в test/folder и запускаем команду python ./packA/subA/subA1.py , то sys.path будет включать в себя test/packA/subA/ , но не test/ .
Кроме того, sys.path общий для всех импортируемых модулей. Допустим, мы вызвали python start.py . Пусть start.py импортирует packA.a1 , а a1.py выводит на экран sys.path . В таком случае sys.path будет включать test/ (путь к start.py ), но не test/packA (путь к a1.py ). Это значит, что a1.py может вызвать import other , так как other.py находится в test/ .
Всё о __init__.py
У файла __init__.py есть две функции:
- Превратить папку со скриптами в импортируемый пакет модулей (до Python 3.3).
- Выполнить код инициализации пакета.
Превращение папки со скриптами в импортируемый пакет модулей
Чтобы импортировать модуль (или пакет) из директории, которая находится не в директории нашего скрипта (или не в директории, из которой мы запускаем интерактивный интерпретатор), этот модуль должен быть в пакете.
Как было сказано ранее, любая директория, содержащая файл __init__.py , является пакетом. Например, при работе с Python 2.7 start.py может импортировать пакет packA , но не packB , так как в директории test/packB/ нет файла __init__.py .
Это не относится к Python 3.3 и выше благодаря появлению неявных пакетов пространств имён. Проще говоря, в Python 3.3+ все папки считаются пакетами, поэтому пустые файлы __init__.py больше не нужны.
Допустим, packB — пакет пространства имён, так как в нём нет __init__.py . Если запустить интерактивную оболочку Python 3.6 в директории test/ , то мы увидим следующее:
>>> import packB >>> packB
Выполнение кода инициализации пакета
В момент, когда пакет или один из его модулей импортируется в первый раз, Python выполняет __init__.py в корне пакета, если такой файл существует. Все объекты и функции, определённые в __init__.py , считаются частью пространства имён пакета.
Рассмотрим следующий пример:
def a1_func(): print("Выполняем a1_func()")
## Этот импорт делает функцию a1_func() доступной напрямую из packA.a1_func from packA.a1 import a1_func def packA_func(): print("Выполняем packA_func()")
import packA # «import packA.a1» сработает точно так же packA.packA_func() packA.a1_func() packA.a1.a1_func()
Вывод после запуска python start.py :
Выполняем packA_func() Выполняем a1_func() Выполняем a1_func()
Примечание Если a1.py вызовет import a2 , и мы запустим python a1.py , то test/packA/__init__.py не будет вызван, несмотря на то, что a2 вроде бы является частью пакета packA . Это связано с тем, что когда Python выполняет скрипт (в данном случае a1.py ), содержащая его папка не считается пакетом.
Использование объектов из импортированного модуля или пакета
Есть 4 разных вида импортов:
Пусть X — имя того, что идёт после import :
- Если X — имя модуля или пакета, то для того, чтобы использовать объекты, определённые в X , придётся писать X.объект .
- Если X — имя переменной, то её можно использовать напрямую.
- Если X — имя функции, то её можно вызвать с помощью X() .
Опционально после любого выражения import X можно добавить as Y . Это переименует X в Y в пределах скрипта. Учтите, что имя X с этого момента становится недействительным. Частым примером такой конструкции является import numpy as np .
Аргументом для import может быть как одно имя, так и их список. Каждое из имён можно переименовать с помощью as . Например, следующее выражение будет действительно в start.py : import packA as pA, packA.a1, packA.subA.sa1 as sa1 .
Пример: нужно в start.py импортировать функцию helloWorld() из sa1.py .
- Решение 1: from packA.subA.sa1 import helloWorld . Мы можем вызвать функцию напрямую по имени: x = helloWorld() .
- Решение 2: from packA.subA import sa1 или то же самое import packA.subA.sa1 as sa1 . Для использования функции нам нужно добавить перед её именем имя модуля: x = sa1.helloWorld() . Иногда такой подход предпочтительнее первого, так как становится ясно, из какого модуля взялась та или иная функция.
- Решение 3: import packA.subA.sa1 . Для использования функции перед её именем нужно добавить полный путь: x = packA.subA.sa1.helloWorld() .
Прим. перев. После переименования с помощью as новое имя нельзя использовать в качестве имени пакета или модуля для последующих импортов. Иными словами, команда вроде следующей недействительна: import packA as pA, pA.a1 .
Используем dir() для исследования содержимого импортированного модуля
После импортирования модуля можно использовать функцию dir() для получения списка доступных в модуле имён. Допустим, мы импортируем sa1 . Если в sa1.py есть функция helloWorld() , то dir(sa1) будет включать helloWorld :
>>> from packA.subA import sa1 >>> dir(sa1) ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'helloWorld']
Импортирование пакетов
Импортирование пакета по сути равноценно импортированию его __init__.py . Вот как Python на самом деле видит пакет:
>>> import packA >>> packA
После импорта становятся доступны только те объекты, что определены в __init__.py пакета. Поскольку в packB нет такого файла, от import packB (в Python 3.3.+) будет мало толку, так как никакие объекты из этого пакета не становятся доступны. Последующий вызов модуля packB.b1 приведёт к ошибке, так как он ещё не был импортирован.
Абсолютный и относительный импорт
При абсолютном импорте используется полный путь (от начала корневой папки проекта) к желаемому модулю.
При относительном импорте используется относительный путь (начиная с пути текущего модуля) к желаемому модулю. Есть два типа относительных импортов:
- При явном импорте используется формат from . import X , где символы точки . показывают, на сколько директорий «вверх» нужно подняться. Одна точка . показывает текущую директорию, две точки .. — на одну директорию выше и т. д.
- Неявный относительный импорт пишется так, как если бы текущая директория была частью sys.path . Такой тип импортов поддерживается только в Python 2.
В документации Python об относительных импортах в Python 3 написано следующее:
Единственный приемлемый синтаксис для относительных импортов — from .[модуль] import [имя]. Все импорты, которые начинаются не с точки ., считаются абсолютными.Источник: What’s New in Python 3.0
В качестве примера допустим, что мы запускаем start.py , который импортирует a1 , который импортирует other , a2 и sa1 . Тогда импорты в a1.py будут выглядеть следующим образом:
import other import packA.a2 import packA.subA.sa1
Явные относительные импорты:
import other from . import a2 from .subA import sa1
Неявные относительные импорты (не поддерживаются в Python 3):
import other import a2 import subA.sa1
Учтите, что в относительных импортах с помощью точек . можно дойти только до директории, содержащей запущенный из командной строки скрипт (не включительно). Таким образом, from .. import other не сработает в a1.py . В результате мы получим ошибку ValueError: attempted relative import beyond top-level package .
Как правило, абсолютные импорты предпочтительнее относительных. Они позволяют избежать путаницы между явными и неявными импортами. Кроме того, любой скрипт с явными относительными импортами нельзя запустить напрямую:
Имейте в виду, что относительные импорты основаны на имени текущего модуля. Так как имя главного модуля всегда "__main__", модули, которые должны использоваться как главный модуль приложения, должны всегда использовать абсолютные импорты.Источник: Python 2 и Python 3
Примеры
Пример 1: sys.path известен заранее
Если вы собираетесь вызывать только python start.py или python other.py , то прописать импорты всем модулям не составит труда. В данном случае sys.path всегда будет включать папку test/ . Таким образом, все импорты можно писать относительно этой папки.
Пример: файлу в проекте test нужно импортировать функцию helloWorld() из sa1.py .
Решение: from packA.subA.sa1 import helloWorld (или любой другой эквивалентный синтаксис импорта).
Пример 2: sys.path мог измениться
Зачастую нам требуется как запускать скрипт напрямую из командной строки, так и импортировать его как модуль в другом скрипте. Как вы увидите далее, здесь могут возникнуть проблемы, особенно в Python 3.
Пример: пусть start.py нужно импортировать a2 , которому нужно импортировать sa2 . Предположим, что start.py всегда запускается напрямую, а не импортируется. Также мы хотим иметь возможность запускать a2 напрямую.
Звучит просто, не так ли? Нам всего лишь нужно выполнить два импорта: один в start.py и другой в a2.py .
Проблема: это один из тех случаев, когда sys.path меняется. Когда мы выполняем start.py , sys.path содержит test/ , а при выполнении a2.py sys.path содержит test/packA/ .
С импортом в start.py нет никаких проблем. Так как этот модуль всегда запускается напрямую, мы знаем, что при его выполнении в sys.path всегда будет test/ . Тогда импортировать a2 можно просто с помощью import packA.a2 .
С импортом в a2.py немного сложнее. Когда мы запускаем start.py напрямую, sys.path содержит test/ , поэтому в a2.py импорт будет выглядеть как from packA.subA import sa2 . Однако если запустить a2.py напрямую, то в sys.path уже будет test/packA/ . Теперь импорт вызовет ошибку, так как packA не является папкой внутри test/packA/ .
Вместо этого мы могли бы попробовать from subA import sa2 . Это решает проблему при запуске a2.py напрямую, однако теперь создаёт проблему при запуске start.py . В Python 3 это приведёт к ошибке, потому что subA не находится в sys.path (в Python 2 это не вызовет проблемы из-за поддержки неявных относительных импортов).

Использование относительного импорта from .subA import sa2 будет иметь тот же эффект, что и from packA.subA import sa2 .
Вряд ли для этой проблемы есть чистое решение, поэтому вот несколько обходных путей:
1. Использовать абсолютные импорты относительно директории test/ (т. е. средняя колонка в таблице выше). Это гарантирует, что запуск start.py напрямую всегда сработает. Чтобы запустить a2.py напрямую, запустите его как импортируемый модуль, а не как скрипт:
- В консоли смените директорию на test/ .
- Запустите python -m packA.a2 .
2. Использовать абсолютные импорты относительно директории test/ (средняя колонка в таблице). Это гарантирует, что запуск start.py напрямую всегда сработает. Чтобы запустить a2.py напрямую, можно изменить sys.path в a2.py , чтобы включить test/packA/ перед импортом sa2 .
import os, sys sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) # Теперь это сработает даже если a2.py будет запущен напрямую from packA.subA import sa2
Примечание Обычно этот метод работает, однако в некоторых случаях переменная __file__ может быть неправильной. В таком случае нужно использовать встроенный пакет inspect . Подробнее в этом ответе на StackOverflow.
3. Использовать только Python 2 и неявные относительные импорты (последняя колонка в таблице).
4. Использовать абсолютные импорты относительно директории test/ и добавить её в переменную среды PYTHONPATH . Это решение не переносимо, поэтому лучше не использовать его. О том, как добавить директорию в PYTHONPATH , читайте в этом ответе.
Пример 3: sys.path мог измениться (вариант 2)
А вот ещё одна проблема посложнее. Допустим, модуль a2.py никогда не надо запускать напрямую, но он импортируется start.py и a1.py , которые запускаются напрямую.
В этом случае первое решение из примера выше не сработает. Тем не менее, всё ещё можно использовать остальные решения.
Пример 4: импорт из родительской директории
Если мы не изменяем PYTHONPATH и стараемся не изменять sys.path программно, то сталкиваемся со следующим основным ограничением импортов в Python: при запуске скрипта напрямую невозможно импортировать что-либо из его родительской директории.
Например, если бы нам пришлось запустить python sa1.py , то этот модуль не смог бы ничего импортировать из a1.py без вмешательства в PYTHONPATH или sys.path .
На первый взгляд может показаться, что относительные импорты (например from .. import a1 ) помогут решить эту проблему. Однако запускаемый скрипт (в данном случае sa1.py ) считается «модулем верхнего уровня». Попытка импортировать что-либо из директории над этим скриптом приведёт к ошибке ValueError: attempted relative import beyond top-level package .
Для решения этой проблемы лучше её не создавать и избегать написания скриптов, которые импортируют из родительской директории. Если этого нельзя избежать, то предпочтительным обходным путём является изменение sys.path .
Python 2 vs Python 3
Мы разобрали основные отличия импортов в Python 2 и Python 3. Они ещё раз изложены здесь наряду с менее важными отличиями:
- Python 2 поддерживает неявные относительные импорты, Python 3 — нет.
- В Python 2, чтобы папка считалась пакетом и её можно было импортировать, она должна содержать файл __init__.py . С версии Python 3.3 благодаря введению неявных пакетов пространств имён все папки считаются пакетами вне зависимости от наличия __init__.py .
- В Python 2 можно написать from import * внутри функции, а в Python 3 — только на уровне модуля.
Ещё немного полезной информации по импортам
- Можно использовать переменную __all__ в __init__.py , чтобы указать, что будет импортировано выражением from import * . Смотрите документацию для Python 2 и Python 3.
- Можно использовать if __name__ == '__main__' для проверки, был ли скрипт импортирован или запущен напрямую. Документация для Python 2 и Python 3.
- Можно установить проект в качестве пакета (в режиме разработчика) с помощью pip install -e , чтобы добавить корень проекта в sys.path . Подробнее в этом ответе на StackOverflow.
- from import * не импортирует имена из модуля, которые начинаются с нижнего подчеркивания _ . Подробнее читайте в документации Python 2 и Python 3.