Что такое пакет python
Перейти к содержимому

Что такое пакет python

  • автор:

Пакеты модулей в Python

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

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

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

Важно помнить, что все пакеты являются модулями, но не все модули являются пакетами. Или, другими словами, пакеты — это просто особый вид модуля. В частности, любой модуль, содержащий атрибут __path__ считается пакетом.

Например есть каталог pkg с двумя модулями mod1.py и mod2.py . Допустим, что содержимое модулей имеет следующий код:

def foo(): print('Модуль 1, функция foo()') 
def bar(): print('Модуль 2, функция bar()') 

Если каталог pkg находится в одном из каталогов, содержащихся в выводе sys.path , то можно импортировать приведенные выше модули, использовав точечную нотацию pkg.mod1 , pkg.mod2 .

Использование конструкции импорта import [, . ] :

>>> import pkg.mod1, pkg.mod2 >>> pkg.mod1.foo() # Модуль 1, функция foo() >>> x = pkg.mod2.bar() >>> x # Модуль 2, функция bar() 

Использование конструкции импорта from import :

>>> from pkg.mod1 import foo >>> foo() # Модуль 1, функция foo() 
>>> from pkg.mod2 import bar as func_bar >>> x = func_bar() >>> x # Модуль 2, функция bar() 

Модули пакета можно импортировать и так — from package import module :

>>> from pkg import mod1 >>> mod1.foo() # Модуль 1, функция foo() >>> from pkg import mod2 as two_mod >>> two_mod.bar() # Модуль 2, функция bar() 

Технически также можно импортировать пакет import pkg . Это синтаксически правильный импорт Python, но он не помещает ни один из модулей пакета pkg в локальное пространство имен скрипта:

>>> import pkg >>> pkg # >>> pkg.mod1 # Traceback (most recent call last): # . # AttributeError: module 'pkg' has no attribute 'mod1' >>> pkg.mod2.bar() # Traceback (most recent call last): # . # AttributeError: module 'pkg' has no attribute 'mod2' 

Чтобы фактически импортировать модули или их содержимое, вам нужно использовать одну из форм, показанных выше.

  • ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
  • Спецификация инструкции import
  • Определение модуля и его импорт
  • Конструкция импорта import modulle as name
  • Конструкция импорта from modulle import names
  • Конструкция импорта from modulle import name as alt_name
  • Как Python ищет импортируемый модуль
  • Список имен, определенных в модуле Python
  • Выполнение модуля как скрипта
  • Перезагрузка модуля
  • Пакеты модулей
  • Файл пакета __init__.py
  • Переменная __all__ в пакетах и модулях
  • Переменная пакета __path__
  • Относительный/абсолютный импорт пакетов
  • Вложенные подпакеты
  • Пространства имен пакета
  • Настройка доступа к атрибутам модуля

Python. Урок 13. Модули и пакеты

Follow us on Google Plus Follow us on rss

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

Модули в Python

Что такое модуль в Python?

Под модулем в Python понимается файл с расширением .py. Модули предназначены для того, чтобы в них хранить часто используемые функции, классы, константы и т.п. Можно условно разделить модули и программы: программы предназначены для непосредственного запуска, а модули для импортирования их в другие программы. Стоит заметить, что модули могут быть написаны не только на языке Python, но и на других языках (например C).

Как импортировать модули в Python?

Самый простой способ импортировать модуль в Python это воспользоваться конструкцией:

import имя_модуля

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

>>> import math >>> math.factorial(5) 120

За один раз можно импортировать сразу несколько модулей, для этого их нужно перечислить через запятую после слова import:

import имя_модуля1, имя_модуля2

>>> import math, datetime >>> math.cos(math.pi/4) 0.707106781186547 >>> datetime.date(2017, 3, 21) datetime.date(2017, 3, 21)

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

import имя_модуля as новое_имя

>>> import math as m >>> m.sin(m.pi/3) 0.866025403784438

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

from имя_модуля import имя_объекта

>>> from math import cos >>> cos(3.14) 0.999998731727539

При этом импортируется только конкретный объект (в нашем примере: функция cos), остальные функции недоступны, даже если при их вызове указать имя модуля.

>>> from math import cos >>> cos(3.14) -0.999998731727539 >>> sin(3.14) Traceback (most recent call last): File "", line 1, in module> sin(3.14) NameError: name 'sin' is not defined >>> math.sin(3.14) Traceback (most recent call last): File "", line 1, in module> math.sin(3.14) NameError: name 'math' is not defined

Для имортирования нескольких функций из модуля, можно перечислить их имена через запятую.

from имя_модуля import имя_объекта1, имя_объекта2

>>> from math import cos, sin, pi >>> cos(pi/3) 0.500000000000000 >>> sin(pi/3) 0.866025403784438

Импортируемому объекту можно задать псевдоним.

from имя_модуля import имя_объекта as псевдоним_объекта

>>> from math import factorial as f >>> f(4) 24

Если необходимо импортировать все фукнции, классы и т.п. из модуля, то воспользуйтесь следующей формой оператора from … import …

from имя_модуля import *

>>> from math import * >>> cos(pi/2) 6.123233995736766e-17 >>> sin(pi/4) 0.707106781186547 >>> factorial(6) 720

Пакеты в Python

Что такое пакет в Python?

Пакет в Python – это каталог, включающий в себя другие каталоги и модули, но при этом дополнительно содержащий файл __init__.py. Пакеты используются для формирования пространства имен, что позволяет работать с модулями через указание уровня вложенности (через точку).

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

Использование пакетов в Python

Рассмотрим следующую структуру пакета:

fincalc |-- __init__.py |-- simper.py |-- compper.py |-- annuity.py

Пакет fincal содержит в себе модули для работы с простыми процентами ( simper.py ), сложными процентами ( compper.py ) и аннуитетами ( annuity.py ).

Для использования фукнции из модуля работы с простыми процентами, можно использовать один из следующих вариантов:

import fincalc.simper fv = fincalc.simper.fv(pv, i, n)
import fincalc.simper as sp fv =sp.fv(pv, i, n)
from fincalc import simper fv = simper.fv(pv, i, n)

Файл __init__.py может быть пустым или может содержать переменную __all__, хранящую список модулей, который импортируется при загрузке через конструкцию

from имя_пакета import *

Например для нашего случая содержимое __init__.py может быть вот таким:

__all__ = ["simper", "compper", "annuity"]

P.S.

Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.

Пакеты и индексы — Python: Настройка окружения

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

Как работают пакеты

Часто пакеты описываются как наборы модулей и вложенных пакетов. Но это не единственное значение этого термина. В более широком смысле пакет — это некая единица обмена кодом между разработчиками.

Python-пакет содержит исходный код и метаданные — дополнительную информацию о пакете, в том числе:

  • Предназначение пакета
  • Текущую версию пакета и список предыдущих версий
  • Совместимость с разными версиями Python
  • Лицензию, под которой распространяется пакет
  • Список зависимостей пакета

Индекс

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

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

Чтобы справиться с этой сложностью, воспользуемся репозиториями пакетов — в Python их принято называть индексами.

Такие индексы содержат пакеты. А еще они предоставляют пользователю удобный интерфейс для поиска пакетов и знакомства с их описанием. Обычно он сделан в виде web-сайта.

Самый популярный индекс пакетов — это PyPI или Python Package Index. Чаще всего вы будете работать именно с ним.

Но есть и другие индексы. Большинство инструментов работы с пакетами могут работать с разными индексами. К примеру, отдельные индексы используются многими компаниями для размещения пакетов, которые не являются открытыми (open source).

Еще один полезный индекс — Test PyPI. Это специальный индекс пакетов, который принято использовать для обучения работе с системой пакетирования Python.

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

Тестовый индекс работает точно так же, как основной PyPI. Он позволяет выкладывать и скачивать пакеты, но периодически удаляет все данные.

Индексы vs GitHub, BitBucket и прочие хранилища кода

В наши дни некоторые репозитории пакетов не хранят пакеты своими силами, а берут на себя только индексацию и управление метаданными пакетов. При этом код предлагается хранить на GitHub, BitBucket, GitLab, другими словами — в хранилищах исходного кода.

Такой подход в целом работает для интерпретируемых языков — в любом случае нужно иметь доступ к исходному коду, чтобы использовать код пакета.

Но хранение кода на сторонних ресурсах по отношению к источнику метаданных обладает рядом недостатков.

Во-первых, опубликованным кодом владеет только автор кода. Автор может удалить свой репозиторий, а информация о пакете в индексе сохранится. Те, кто уже начал использовать пакет, столкнутся с невозможностью сборки своих проектов.

Во-вторых, GitHub и другие хранилища Git-репозиториев не гарантирует неизменность данных в репозитории при использовании одних только тегов и веток. А ведь именно такой способ привязки состояния кода к информации в индексе и используется чаще всего — то есть любой обладатель доступа к репозиторию может переписать его историю. Даже если привязывать версии пакетов в индексе к hash-суммам коммитов в Git, то изменение в истории приведет к первой проблеме — версия пакета будет ссылаться на несуществующий источник кода. При переписывании истории hash-суммы коммитов тоже поменяются.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Python модули и пакеты

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

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

Модули также могут быть написаны и на других языках, но данная статья направлена на рассмотрение использования данного механизмах в рамках Python.

Модули

В языке программирования Python модулями являются все файлы с расширением *.py (* обозначает, что на этом месте может стоять любой символ или любое их количество). Исключением является служебный файл __init__.py (о назначении которого описано далее в статье).

Дальше стоит понимать, что любая программа имеет некую точку входа. Это своего рода место с которого стартует наш скрипт. В языках предшественниках данной точкой служила функция main и могла быть лишь только одной. В нашем случае допускается отсутствие таковой, но это снижает качество кода, делая его сложным и малопредсказуемым(при импорте код содержащийся на верхнем уровне исполняется). Для того чтобы указать точку входа(может быть указана только в модулях) используется специальная переменная __name__ , в которой содержится наименование текущего модуля или пакета. Если текущий модуль находится на верхнем уровне исполнения(мы явно его передали на исполнение Python), то он называется __main__ независимо от названия файла.

# Указание входной точки ## Если __name__ равно "__main__" исполни if __name__ == "__main__": print('Я главный!') # Вызов других функций, например main()

Для примера реализуем простой модуль, который будет возвращать нам информацию:

# http_get.modules.http_get # Расположен в дирректории http_get, modules и назван http_get def get_dict(): return # Поскольку зависимых импортов нет, мы можем исполнить этот код для проверки # Т.е. в качестве входной точки использовать нашу функцию # Данный код исполнится только, когда этот файл будет исполняемым(не импортируемым) if __name__ == '__main__': print(get_dict())

Далее в корне создадим main.py файл, в который импортируем наш модуль двумя разными способами(об импортах описано в статье):

# main.py from ModulesAndPackages.module_examples.http_get.modules.http_get import get_dict as absolute from http_get.modules.http_get import get_dict as relative def main(): # Работает print(absolute()) print(relative()) if __name__ == '__main__': main()

Все без проблем исполняется.

Трудности

При переносе файлов куда-либо из директории возникнут проблемы из-за первого импорта( main.py ). Поскольку часто приходится писать один и тот же код, использование уже хорошо написанного пакета или модуля может экономить много времени, но исправление большого количества импортов требует Ваших ресурсов. Хорошо написанный пакет, модуль или импорт может экономить ваши рабочие часы, а иногда и нервы.

Не изменяя наши модули(импорты), при изменении положения файлов возникает ошибка импорта:

# Не работает в другом проекте from ModulesAndPackages.module_examples.http_get.modules.http_get import get_dict as absolute # Всегда работает from http_get.modules.http_get import get_dict as relative def main(): print(absolute()) print(relative()) if __name__ == '__main__': main()

Пакеты

В языке программирования Python пакетами являются все директории(вне зависимости от наличия в них модулей), содержащие файл __init__.py , который исполняется при импорте пакета и несет его название ( __name__ ).

Для примера реализуем простой пакет( package ), на базе вышеописанного модуля( http_get.py ):

# package/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict())
# package/__init__.py from .modules.http_get import get_dict . def get_data(): return get_dict() . # Не работает # __init__ не может иметь точки входа # # if __name__ == '__main__': # get_data()

А также реализуем простой пакет с такой же логикой, но с использованием абсолютного импорта:

# package_2/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict()) 
# package_2/__init__.py from ModulesAndPackages.package_examples.package_2.modules.http_get import get_dict . def get_data(): return get_dict() . # Не работает # __init__ не может иметь точки входа # # if __name__ == '__main__': # get_data()

В корне директории(на уровень выше пакета) создадим файл, в котором воспользуемся нашими пакетами( main.py ):

# main.py from package import get_data from package_2 import get_data as get_data_2 def main(): # Работает print(get_data()) print(get_data_2()) if __name__ == '__main__': main()

Все работает без ошибок.

Трудности

Но при переносе нашего package_2 в другой проект, он теряет свою работоспособность из-за ошибки импортирования в __init__.py файле, в отличии от package .

# package_transferring/package/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict())
# package_transferring/package/__init__.py from .modules.http_get import get_dict . def get_data(): return get_dict() . # Не работает # __init__ не может иметь точки входа # # if __name__ == '__main__': # get_data()
# package_transferring/package_2/modules/http_get.py def get_dict(): return if __name__ == '__main__': print(get_dict())
# package_transferring/package_2/__init__.py # Ошибка импорта т.к. изменилась директория from ModulesAndPackages.package_examples.package_2.modules.http_get import get_dict . def get_data(): return get_dict() . # Does not work! # Because init file in package could not have entry point # # if __name__ == '__main__': # get_data()
# package_transferring/main.py from package import get_data # Ошибка импорта from package_2 import get_data as get_data_2 def main(): print(get_data()) print(get_data_2()) if __name__ == '__main__': main()

P.S.

Данная статья написана для новичков, которые изучают язык программирования Python. Задача которой продемонстрировать на простых примерах способы написания пакетов и модулей(не является туториалом), а так же показать какие трудности могут возникнуть и пути их решения.

Github с проектом к данной статье: ModulesAndPackages

Может быть полезно выгрузить модуль или пакет и попробовать внедрить его в свой проект.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *