Импортировать модуль из родительского каталога в пакетах

1

Я упомянул несколько потоков и статей, в том числе:

но не может получить желаемый результат.

Скажем, у меня есть каталог под названием "helloworld":

helloworld
|--__init__.py
|--say_hello.py
|--another_hello
   |--__init__.py
   |--import_hello.py

Это say_hello.py:

def hello_world():
    print("Hello World!")
if __name__ == "__main__":
    hello_world()

Это import_hello.py:

from .. import say_hello
say_hello.hello_world()

Я надеюсь импортировать модуль say_hello везде, где я называю python/path/to/import_hello.py без использования sys модуля.

Однако теперь, когда я выполняю python/path/to/import_hello.py, он вернет ValueError: attempted relative import beyond top-level package, и я понятия не имею, почему он не работает.

Даже это не работает:

from helloworld import say_hello
say_hello.hello_world()

Это даст мне ModuleNotFoundError: No module named 'helloworld'.

Теги:
python-3.x
python-import

2 ответа

1
Лучший ответ

Вы не можете запускать скрипт из середины пакета. Когда вы это делаете, вы не используете helloworld.another_hello.import_hello из /path/to/helloworldsparent/, вы используете __main__ основе /path/to/helloworldsparent/helloworld/another_hello. Таким образом, у него нет родительского пакета для import как ..


Вы можете запустить модуль с помощью -m:

$ python -m helloworld.another_hello.import_hello

... предполагая, helloworld каталог helloworld находится на вашем sys.path (например, потому, что вы установили его в site-packages или потому, что ваш текущий рабочий каталог является его родителем или потому, что вы настроили PYTHONPATH).


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

import helloworld.another_hello.import_hello
helloworld.another_hello.import_hello.main()

Если вы используете setuptools (и вы действительно должны быть для чего-то достаточно сложного, чтобы обладать двумя уровнями пакетов), вы можете заставить его автоматически создавать сценарии точки входа во время установки (или во время --inplace во время разработки). См. Раздел " Создание автоматического сценария" в документах (но вам, вероятно, потребуется прочитать и другие разделы, чтобы получить всю идею, документы довольно большие и сложные).

  • 0
    Благодарю. Но я не совсем понимаю, что такое «оставить глубокие модули в покое» при использовании setuptools . Означает ли это, что я могу оставить import_hello.py как сейчас, т.е. from .. import say_hello; say_hello.hello_world() ?
  • 0
    @ytu Строка from … import будет работать, но вы обычно хотите переместить код верхнего уровня (например, say_hello.hello_world() ) в функцию, которая может быть вызвана кем-то после import helloworld.another_hello.import_hello , а не после он будет запущен в первый раз, когда кто-нибудь сделает этот import в процессе. Другими словами, вы хотите модули, а не скрипты, внутри пакетов.
Показать ещё 1 комментарий
0

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

from sys import path as pylib
import os
pylib += os.path.abspath('..')
from helloworld import say_hello

Надеюсь, поможет !!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню