Імпорт сценарію з батьківського каталогу


81

Як імпортувати модуль (файл python), який знаходиться в батьківському каталозі?

В обох каталогах є __init__.pyфайл, але я все ще не можу імпортувати файл із батьківського каталогу?

У цьому макеті папок сценарій B намагається імпортувати сценарій A:

Folder A:
   __init__.py
   Script A:
   Folder B:
     __init__.py
     Script B(attempting to import Script A)

Наступний код у сценарії B не працює:

import ../scriptA.py # I get a compile error saying the "." is invalid

Не точно відповісти на ваше запитання, але якщо ви запустите init .py всередині папки A і спробуєте імпортувати папку B або сценарій B, сценарій A буде успішно імпортовано всередину сценарію B.
Michael0x2a

Відповіді:


78

Ви не імпортуєте сценарії в Python, а імпортуєте модулі. Деякі модулі python - це також сценарії, які можна запускати безпосередньо (вони виконують корисну роботу на рівні модуля).

Загалом переважно використовувати абсолютний імпорт, а не відносний імпорт.

toplevel_package/
├── __init__.py
├── moduleA.py
└── subpackage
    ├── __init__.py
    └── moduleB.py

В moduleB:

from toplevel_package import moduleA

Якщо ви хочете запустити moduleB.pyяк скрипт, переконайтесь, що батьківський каталог для toplevel_packageзнаходиться у вашому sys.path.


8
І чому б у цьому випадку не використовувати "хаки" sys path? Python робить так важко робити те, що ти хочеш, без них. Який саме мінус тут?
BT

4
@BT « sys.path.append(path_to_parent)» не повинен відповідати на те, як виправити «" import ../scriptA.py # Я отримую помилку компіляції, кажучи, що питання "." Недійсне "» . Є випадки, коли зміна sys.pathможе бути корисною, наприклад, якщо це зробив сам python, або 3-сторонній модуль, який обробляє всі кутові випадки правильно, наприклад, import autopath; autopath.add_toplevel_to_syspath()що автоматично додає батьківський каталог toplevel_package, sys.pathщоб дозволити безпосереднє внутрішнє виконання модуля як скрипт (або в REPL) з будь-якого каталогу без належного встановлення PYTHONPATH або (virtualenv).
jfs

3
@JFSebastian Чи є якась пропозиція щодо функції, яка дозволяє нам чітко сказати, що є основною папкою або пакетом всього проекту, щоб нам не потрібно було дбати про додавання батьківських каталогів, щоб sys.pathми могли запускати підмодулі також як основні файли чи сценарії? У мене є проект, де мені дійсно потрібно запускати сценарії як як основні, так і як модулі, що імпортується, але мені потрібно зробити безліч хаків, додаючи шляхи, щоб sys.pathвони працювали в обох випадках. Чи буде працювати як-небудь робота у virtualenv або використання setuptools? Я справді борюся з цим ...
nbro

2
@nbro ця функція називається pip install main-package. Ви вже можете запускати "підмодулі" (просто використовуйте їх абсолютні назви, наприклад, python -ma.b.c). Якщо незрозуміло; ask
jfs

11
Це рішення для мене не працює. Піднімається: "ImportError: Немає модуля з іменем toplevel_package"
розумний

35

З документів :

from .. import scriptA

Це можна зробити в пакунках, але не в сценаріях, які ви запускаєте безпосередньо. За посиланням вище:

Зауважте, що як явний, так і неявний відносний імпорт базуються на назві поточного модуля. Оскільки ім'я головного модуля завжди "__main__", модулі, призначені для використання в якості основного модуля програми Python, повинні завжди використовувати абсолютний імпорт.

Якщо ви створите сценарій, який імпортує ABB, ви не отримаєте ValueError.


29
ValueError: Спроба відносного імпорту в не-пакунку
jgritty

3
@jgritty, це тому, що ви робите це в сценарії, який ви запускаєте безпосередньо.
Роб Воутерс,

2
Так, ви праві. Це буде працювати, якщо ви викликаєте сценарій, який потім імпортує сценарій B.
jgritty

6
@jgritty sys.path.append("..")- це те, що ви шукаєте

5
Нарешті, через 6 років, фрагмент коду, який я шукав!
jgritty

5

Якщо ви хочете запустити сценарій безпосередньо, ви можете:

  1. Додайте шлях FolderA до змінної середовища ( PYTHONPATH).
  2. Додайте шлях до sys.pathвашого сценарію.

Тоді:

import module_you_wanted
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.