Импорт пакетов в Python
Я, вероятно, пропустил что-то очевидное, но в любом случае:
Когда вы импортируете пакет, например os
в python, вы можете использовать любые подмодули/подпакеты с места в карьер. Например, это работает:
>>> import os
>>> os.path.abspath(...)
Однако у меня есть собственный пакет, который структурирован следующим образом:
FooPackage/
__init__.py
foo.py
и здесь та же логика не работает:
>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'
Что я делаю неправильно?
Ответы
Ответ 1
Вам нужно импортировать подмодуль:
import FooPackage.foo
То, что вы делаете, ищет foo
в FooPackage/__init__.py
. Вы могли бы решить это, поставив import FooPackage.foo as foo
(или from . import foo
) в FooPackage/__init__.py
, тогда Python сможет найти там foo
. Но я рекомендую использовать мое первое предложение.
Ответ 2
Когда вы импортируете FooPackage
, Python ищет каталоги на PYTHONPATH, пока не найдет файл с именем FooPackage.py
или каталог с именем FooPackage
, содержащий файл с именем __init__.py
. Однако, найдя каталог пакета, он не сканирует этот каталог и автоматически импортирует все .py файлы.
Есть две причины такого поведения. Во-первых, при импорте модуля выполняется код Python, который может занять время, память или иметь побочные эффекты. Поэтому вы можете импортировать a.b.c.d
без обязательного импорта всего огромного пакета a
. Разработчик пакета должен решить, должен ли __init__.py
явно импортировать свои модули и подпакеты, чтобы они всегда были доступны, или же или оставляет клиентскую программу возможностью выбирать и выбирать загружаемую.
Второе немного более тонкое, а также шоустоппер. Без явного оператора import (либо в FooPackage/__init__.py
, либо в клиентской программе) Python не обязательно знает, какое имя должно импортировать foo.py
as. В нечувствительной к регистру файловой системе (например, используемой в Windows) это может представлять собой модуль с именем foo
, foo
, foo
, foo
, foo
, foo
, foo
или foo
. Все они являются действительными, отличными идентификаторами Python, поэтому Python просто не располагает достаточной информацией из файла, чтобы знать, что вы имеете в виду. Поэтому для того, чтобы вести себя последовательно во всех системах, для этого требуется явный оператор импорта, чтобы уточнить имя, даже в файловых системах, где доступна полная информация о случаях.
Ответ 3
Вам нужно добавить from . import foo
в файл __init__.py
в вашем пакете.
Ответ 4
Существуют некоторые важные заблуждения, которые необходимо решить, в частности, с терминологией. Во-первых, обычно, когда вы думаете, что импортируете package
в python, то, что вы фактически импортируете, является module
. Вы должны использовать термин " package
когда вы думаете о подструктуре файловой системы, которая поможет вам организовать ваш код. Но с точки зрения кода, всякий раз, когда вы импортируете package
, Python рассматривает его как модуль. Все пакеты являются модулями. Не все модули являются пакетами. Модуль с атрибутом __path__
считается пакетом.
Вы можете проверить, что os
является модулем. Чтобы подтвердить это, вы можете:
import os
print(type(os)) # will print: <type 'module'>
В вашем примере, когда вы import FooPackage
, FooPackage
рассматривается и считается модулем, а его атрибуты (функции, классы и т.д.) Предположительно определены в __init__.py
. Поскольку ваш __init__.py
пуст, он не может найти foo
.
За пределами import
заявлений вы не можете использовать '.'
нотация для адреса модулей внутри модулей. Единственное исключение происходит, если module
импортируется в файл родительского пакета предполагаемого __init__.py
. Чтобы было ясно, давайте сделаем несколько примеров здесь:
Рассмотрите свою первоначальную структуру:
FooPackage/
__init__.py
foo.py
Случай 1: __init__.py - пустой файл
#FooPackage imported as a module
import FooPackage
#foo is not a name defined in '__init__.py'. Error
FooPackage.foo
#FooPackage.foo imported as a module
import FooPackage.foo
#Error, foo has not been imported. To be able to use foo like this,
#you need to do: import FooPackage.foo as foo
foo.anything
#Not error, if anything is defined inside foo.py
FooPackage.foo.anything
Случай 2: __init__.py имеет import foo
строки в нем:
import FooPackage
#Now this is good. 'foo' is sort of considered to be an attribute of
#FooPackage
FooPackage.foo
Теперь предположим, что foo больше не является module
, а function
которую вы определяете в __init__.py
. если вы import FooPackage.foo
, это вызовет ошибку, говоря, что foo
не является модулем.
Ответ 5
Вы можете импортировать пакет из библиотеки с помощью оператора import.
синтаксис: import module_name
ex: import math
Вы можете импортировать только определенный метод из пакета с помощью синтаксиса ударов
Синтаксис : from module_name import function_name
ex: from math import radians