Импортировать модуль из относительного пути - PullRequest
731 голосов
/ 11 ноября 2008

Как импортировать модуль Python с учетом его относительного пути?

Например, если dirFoo содержит Foo.py и dirBar, а dirBar содержит Bar.py, как мне импортировать Bar.py в Foo.py?

Вот визуальное представление:

dirFoo\
    Foo.py
    dirBar\
        Bar.py

Foo хочет включить Bar, но реструктуризация иерархии папок невозможна.

Ответы [ 23 ]

0 голосов
/ 25 июля 2018

Это также работает и намного проще, чем что-либо с модулем sys:

with open("C:/yourpath/foobar.py") as f:
    eval(f.read())
0 голосов
/ 09 ноября 2017

У меня нет опыта работы с Python, поэтому, если в моих словах что-то не так, просто скажите мне. Если ваша файловая иерархия устроена так:

project\
    module_1.py 
    module_2.py

module_1.py определяет функцию с именем func_1(), module_2.py :

from module_1 import func_1

def func_2():
    func_1()

if __name__ == '__main__':
    func_2()

и вы запускаете python module_2.py в cmd, он запускает то, что определяет func_1(). Обычно мы импортируем одни и те же файлы иерархии. Но когда вы пишете from .module_1 import func_1 в module_2.py, интерпретатор Python скажет No module named '__main__.module_1'; '__main__' is not a package. Таким образом, чтобы исправить это, мы просто сохраняем изменения, которые мы просто вносим, ​​и перемещаем оба модуля в пакет, и создаем третий модуль в качестве вызывающей стороны для запуска module_2.py.

project\
    package_1\
        module_1.py
        module_2.py
    main.py

main.py

from package_1.module_2 import func_2

def func_3():
    func_2()

if __name__ == '__main__':
    func_3()

Но причина, по которой мы добавляем . перед module_1 в module_2.py, заключается в том, что если мы не сделаем этого и не запустим main.py, интерпретатор python скажет No module named 'module_1', это немного сложно, module_1.py прямо рядом с module_2.py. Теперь я позволю func_1() in module_1.py сделать что-то:

def func_1():
    print(__name__)

, который __name__ записывает, кто вызывает func_1. Теперь мы сохраняем значение . до module_1, запускаем main.py, будет напечатано package_1.module_1, а не module_1. Это указывает на то, что тот, кто вызывает func_1(), находится в той же иерархии, что и main.py, . означает, что module_1 находится в той же иерархии, что и module_2.py. Поэтому, если точки нет, main.py распознает module_1 в той же иерархии, что и она, он может распознавать package_1, но не то, что «под» ней.

Теперь давайте немного усложним. У вас есть config.ini, и модуль определяет функцию для чтения в той же иерархии, что и main.py.

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
    main.py

И по какой-то неизбежной причине вы должны вызывать его с module_2.py, поэтому он должен импортироваться из верхней иерархии. module_2.py :

 import ..config
 pass

Две точки означают импорт из верхней иерархии (три точки имеют доступ выше верхней и т. Д.). Теперь мы запускаем main.py, переводчик скажет: ValueError:attempted relative import beyond top-level package. "Пакет верхнего уровня" здесь main.py. Просто потому, что config.py находится рядом с main.py, они находятся в той же иерархии, config.py не находится "под" main.py, или оно не "приведено" к main.py, поэтому оно превышает main.py , Чтобы исправить это, самый простой способ:

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
main.py

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

0 голосов
/ 22 сентября 2011

Называйте меня чрезмерно осторожным, но мне нравится делать мой более переносимым, потому что небезопасно предполагать, что файлы всегда будут находиться в одном месте на каждом компьютере. Лично у меня есть код, сначала найдите путь к файлу. Я использую Linux, так что мой будет выглядеть так:

import os, sys
from subprocess import Popen, PIPE
try:
    path = Popen("find / -name 'file' -type f", shell=True, stdout=PIPE).stdout.read().splitlines()[0]
    if not sys.path.__contains__(path):
        sys.path.append(path)
except IndexError:
    raise RuntimeError("You must have FILE to run this program!")

Это, конечно, если вы не планируете собрать их вместе. Но если это так, вам все равно не нужны два отдельных файла.

...