Понимание приоритета импорта Python


Мне нужно пояснить, как обрабатывается импорт на уровне модуля и класса при сосуществовании в одном пространстве имен. См. следующие примеры:

Работает:

import datetime
print datetime.datetime.utcnow()

Неудача:

from datetime import datetime
print datetime.datetime.utcnow()

Ошибка: AttributeError: тип объекта ' datetime.датавремя' нет атрибут 'datetime'

Работает:

from datetime import datetime # Is this ignored?
import datetime
print datetime.datetime.utcnow()

Что именно происходит в 3-м примере? Заменяет ли импорт второго модуля первый импорт, относящийся к определенному классу? Означает ли это, что импорт модулей и классов не должен смешиваться в одном пространстве имен?

5 2

5 ответов:

Нет такого приоритета. Результат определяется порядком выполнения операторов import следующим образом.

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

Поэтому в конце это будет последний импорт, который будет действовать в том, что касается имени X.

Именно это и происходит в вашем третьем примере:

from datetime import datetime # This isn't ignored, but the name is immediately rebound
                              # by the next line
import datetime               # Rebinds the name

Некоторые IDE, поддерживающие python, дадут вам объяснение, но да, вы переопределяете (перезаписываете, заменяете) импорт в 3-м примере. Каждое имя в файле различно. Если вам нужен доступ к модулю и классу, которые имеют общее имя, вам нужно использовать что-то вроде from datetime import datetime as dt.

Импорт-это на самом деле просто назначение: он задает имя в текущем пространстве имен. Итак, в третьем случае вы устанавливаете имя datetime равным классу datetime, а затем немедленно переназначаете его модулю datetime.

Нет никаких причин делать это так:

from datetime import datetime
print datetime.datetime.utcnow()

Этот код, с другой стороны, будет делать именно то, что вы хотите:

from datetime import datetime
print datetime.utcnow()

Ваш первый пример импортирует модуль datetime и предоставляет метку datetime в локальном пространстве имен, представляющем его, а затем вызывает метод utcnow() объекта datetime, принадлежащего модулю datetime. Второй добавляет объект datetime.datetime (Не модуль) в локальное пространство имен с меткой datetime, но объект datetime не имеет атрибута datetime, поэтому вы получаете исключение. В третьем примере объект datetime.datetime присваивается метке этого имени в пространстве имен, а затем переназначается метке модуля datetime. Таким образом, игнорируя механику import, которая не имеет отношения к этому вопросу (в основном, добавляя модули к sys.modules, если они еще не существуют), то, что у вас есть, эквивалентно:

datetime = sys.modules['datetime']
datetime.datetime.utcnow()

Затем

datetime = sys.modules['datetime'].datetime
datetime.datetime.utcnow()

Затем

datetime = sys.modules['datetime'].datetime
datetime = sys.modules['datetime']
datetime.datetime.utcnow()