Семантика оператора импорта python
Я начинающий python, и мне трудно понять оператор импорта и его варианты.
Предположим, что я использую модуль lxml для очистки веб-сайтов.
В примерах показано,
from lxml.html import parse
parse( 'http://somesite' )
Руководство по стилю python Google предпочитает основной оператор импорта, чтобы сохранить пространства имен. Я бы предпочел сделать это, но когда я попробую:
import lxml
lxml.html.parse( 'http://somesite' )
Появляется следующее сообщение об ошибке:
AttributeError: объект 'module' не имеет атрибута 'html'
Может ли кто-нибудь помочь мне понять, что происходит? Я бы предпочел использовать модули в своих пространствах имен, но вам нужна помощь в понимании семантики.
Большое значение.
Ответы
Ответ 1
import lxml.html as LH
doc = LH.parse('http://somesite')
lxml.html
является модулем. Когда вы import lxml
, модуль html
не импортируется в пространство имен lxml
. Это решение разработчика. Некоторые пакеты автоматически импортируют некоторые модули, некоторые - нет. В этом случае вы должны сделать это самостоятельно с помощью import lxml.html
.
import lxml.html as LH
импортирует модуль html
и связывает его с именем LH
в текущем пространстве имен модулей. Таким образом, вы можете получить доступ к функции parse с помощью LH.parse
.
Если вы хотите глубже погрузиться, когда пакет (например, lxml
) автоматически импортирует модули (например, lxml.html
), откройте терминал и введите
In [16]: import lxml
In [17]: lxml
Out[17]: <module 'lxml' from '/usr/lib/python2.7/dist-packages/lxml/__init__.pyc'>
Здесь вы видите путь к файлу lxml
package __init__.py
.
Если вы посмотрите на содержимое, которое вы обнаружите, оно пустое. Таким образом, никакие подмодули не импортируются. Если вы посмотрите в numpy __init__.py
, вы увидите много кода, среди которых
import linalg
import fft
import polynomial
import random
import ctypeslib
import ma
Это все подмодули, которые импортируются в пространство имен numpy
. Поэтому с точки зрения пользователя import numpy
автоматически предоставляет вам доступ к numpy.linalg
, numpy.fft
и т.д.
Ответ 2
Возьмем пример пакета pkg
с двумя модулями в нем a.py
и b.py
:
--pkg
|
| -- a.py
|
| -- b.py
|
| -- __init__.py
в __init__.py
вы импортируете a.py
и не b.py
:
импортировать
Итак, если вы открываете терминал и выполняете:
>>> import pkg
>>> pkg.a
>>> pkg.b
AttributeError: 'module' object has no attribute 'b'
Как вы можете видеть, поскольку мы импортировали a.py
в pkg __init__.py
, мы смогли получить к нему доступ как атрибут pkg
, но b
там нет, поэтому для доступа к этому позже мы должны использовать:
>>> import pkg.b # OR: from pkg import b
НТН,
Ответ 3
Когда вы import
пакет, интерпретатор просматривает пакет на pythonpath, затем, если найден, анализирует и запускает пакет __init__.py
, строит из него объект пакета и вставляет этот объект в sys.modules
, Когда importing
модуль, он делает то же самое, кроме того, что создает и добавляет объект модуля. Когда вы впоследствии пытаетесь получить доступ к атрибуту (также как метод-член, класс, подмодуль или подпакет), он извлекает соответствующий объект из sys.modules
и пытается выполнить getattr
в модуле или объекте пакета для нужного вам ребенка. Однако, если дочерний объект является подмодулем или подпакетом, который еще не был imported
, он не был добавлен в sys.modules
или список атрибутов модуля или пакета, поэтому вы получите AttributeError
. Таким образом, вы должны явно импортировать модуль или пакет либо в свой код, либо делегировать его в пакете __init__.py
, чтобы он был доступен во время выполнения для его родителя.