2016-08-18 5 views
0

, если у меня есть каталог, как этотИмпорт из родительского каталога в файл подпапки с помощью __init__?

dir_one/ 
    main.py 
    __init__.py 
    dir_two/ 
     sub.py 
     __init__.py 

оба моих INIT .py файлов в настоящее время пуст. В моем файле sub.py я пытаюсь импортировать класс из main.py: , например.

#File:sub.py 
from main import items 

Какой из них не работает. Я также пробовал

#File:sub.py 
from dir_one.main import items 

который также не работал.

Есть ли способ импортировать файл main.py из sub.py? Нужно ли мне редактировать __init__.py, учитывая, что он пуст?

+0

Какой скрипт вы вызываете? Вы пытаетесь запустить 'sub.py' напрямую (a.la' python dir_one/dir_two/sub.py')? Или вы импортируете 'sub.py' из другого места, и он не работает в этот момент? – mgilson

+0

Я пытаюсь запустить sub.py напрямую – kwotsin

+0

Ahh - В этом проблема. Обычно модули в пакетах не должны запускаться напрямую. Обычно способ структурирования этих вещей состоит в том, что у вас должен быть отдельный каталог (например, 'scripts', который импортирует пакет (и утилит в нем), который предоставляет точку входа в программу. – mgilson

ответ

1

У вас есть несколько вариантов здесь.

Ваш лучший вариант - сохранить пакеты отдельно от сценариев, которые используют пакет. Посмотрите на entry_points для setuptools. Вы указываете setuptools на функцию в вашем пакете и создаете скрипт, чтобы вызвать его. Острота ...

В играя с этим, я создал следующую структуру пакета:

test_dir 
    + __init__.py 
    + main.py 
    + sub1 
    --+ __init__.py 
    --+ script.py 
    + sub2 
    --+ __init__.py 
    --+ module.py 

и я убедился, что test_dir доступен через PYTHONPATH.

Сценарии все супер просто (только печать некоторые вещи):

# main.py 
def func_in_main(): 
    print("Hello from main.py!") 

# module.py 
def run_func(): 
    print("Hello from script in sub2.py!") 

# script.py 
from ..sub2 import module 
from .. import main 

def entry_point(): 
    module.run_func() 
    main.func_in_main() 

if __name__ == '__main__': 
    entry_point() 

Теперь, что произойдет, если я пытаюсь запустить это напрямую?

$ python test_package/test_dir/sub1/script.py 
Traceback (most recent call last): 
    File "test_package/test_dir/sub1/script.py", line 2, in <module> 
    from ..sub2 import module 
ValueError: Attempted relative import in non-package 

Хм ... Облом (это тот случай, когда я пытался описать в комментариях к исходному вопросу). Это происходит независимо от моего текущего рабочего каталога, кстати ... Тем не менее, из любого места на моей файловой системе, я могу запустить это с помощью -m флага :

$ python -m test_dir.sub1.script 
Hello from script in sub2.py! 
Hello from main.py! 

Horray! Нам нужно только указать путь к модулю, а затем мы золотые (помните, что test_dirДОЛЖЕН быть доступным через ваш PYTHONPATH, чтобы это работало). Хорошо, но что, если мы действительно хотим вызвать скрипт вместо использования пути к модулю?Если это так, то мы можем изменить переменную __package__, прежде чем делать какие-либо импортирование:

# script.py (updated) 
if __name__ == '__main__' and __package__ is None: 
    __package__ = 'test_dir.sub1' 
    import test_dir # needed to suppress SystemError -- I'm not sure why... 

from .. import main 
from ..sub2 import module 

def entry_point(): 
    module.run_func() 
    main.func_in_main() 

if __name__ == '__main__': 
    entry_point() 

Теперь попробуем запустить эту вещь прямо снова:

$ python test_package/test_dir/sub1/script.py 
test_package/test_dir/sub1/script.py:4: RuntimeWarning: Parent module 'test_dir.sub1' not found while handling absolute import 
    import test_dir 
Hello from script in sub2.py! 
Hello from main.py! 

Мы все еще получить RuntimeWarning, но это работает Ok. Для получения дополнительной информации см. PEP-0366.

В общем, я запускать большинство из них из-за пределов пакета (один уровень выше test_dir), но примеры работы, если я запускаю его из внутри пакета, а также. с -m вы всегда указываете полный путь к модулю (test_dir.sub1.script), без него вы указываете только относительный или абсолютный путь к файлу)

1

В файле sub.py вы могли бы сделать что-то вроде

import os 

wd = os.getcwd() # save current working directory 
os.chdir('path/to/dir_one') # change to directory containing main.py 
from main import items # import your stuff 
os.chdir(wd) # change back to directory containing sub.py 

перед использованием ваших деталей образует основным.

Edit: В вашем конкретном случае бы просто один каталог вверх, т.е. '..'

Смежные вопросы