Ошибка в интерпретаторе Python или я неправильно понимаю механизм импорта пакетов? - PullRequest
0 голосов
/ 22 апреля 2019

У меня есть следующее дерево исходников:

planets/
    earth.py
    mars.py
util.py
main.py

Со следующим кодом:

planets / earth.py:

def moon() -> None:
    print('moon')

planets / mars.py:

def phobos() -> None:
    print('phobos')

util.py:

import planets.mars  # yes, just this

main.py:

import planets.earth
import util

def foobar() -> None:
    planets.mars.phobos()

if __name__ == '__main__':
    foobar()

Обратите внимание, что в "main.py" я не указываю явноимпорт "planets.mars".Когда я запускаю «main.py», вместо того, чтобы получить ошибку, как я ожидал, я получаю вывод:

phobos

Мне кажется, что, поскольку я импортирую «planets.mars» в «util».py ", а затем я импортирую" util.py "в" main.py "," main.py "может видеть" planets.mars "и, таким образом, я могу вызвать" planets.mars.phobos () "из" main.py".

Однако, когда я удаляю" import planets.earth "из" main.py ", я получаю исключение" NameError: name 'planets' notfined "при попытке запустить" main.py ",Похоже, это указывает на то, что «planets.mars», транзитивно импортируемый в «main.py» путем импорта в «util.py», - это не то, что происходит, и в действительности происходит ошибка в моем интерпретаторе Python.

Может кто-нибудь пролить свет на эту загадку для меня?Я использую CPython версии 3.7.0 в Debian 9.

Спасибо!

1 Ответ

3 голосов
/ 22 апреля 2019

Импорт planets.earth добавляет модуль planets в пространство имен main.py и вставляет planets и planets.earth в sys.modules.

Импорт planets.mars в util.py вставляет planets.mars в sys.modules и делает имя mars доступным в качестве атрибута planets.

При обращении к planets.mars.phobos в main.py, к planet.mars можно получить доступ через имя planets в пространстве имен main.py.

Если импорт planets.earth удален из main.py, planets больше не находится в пространстве имен модуля, поэтому NameError повышается.

Если импорт util.py удален, mars не устанавливается как атрибут planets и, следовательно, AttributeError повышается.

Такое поведение может сбивать с толку, и это одна из причин, по которой многие пакеты имеют __init__.py, который импортирует субмодуль / подпакеты, чтобы они все были доступны при импорте пакета.

...