Импорт файлов из другой папки

avatar
Ivan
8 декабря 2010 в 02:07
2199515
35
1927

У меня следующая структура папок.

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

Я хочу импортировать некоторые функции из file.py в some_file.py.

Я пробовал

from application.app.folder.file import func_name

и другие различные попытки, но пока мне не удалось правильно импортировать. Как я могу это сделать?

Источник
wim
18 апреля 2017 в 15:56
2

Связанный: coderhelper.com/q/43476403/674039

Kavin Raju S
14 мая 2020 в 01:20
0

Мне очень помогло чтение официальной документации! docs.python.org/3/reference/…

Gonzalo
28 апреля 2021 в 15:01
0

Если у вас есть тире в имени подпапки, она ДОЛЖНА БЫТЬ ЗНАЧИТЕЛЬНОЙ. Например, my-package, а внутри у вас есть папка my_app и папка тестов. Если my_app называется my-app, у вас возникнут проблемы с импортом

smci
14 июня 2021 в 23:26
0

Ни application, ни app1, app2, folder, some_folder не являются пакетами и не содержат __init__.py, верно? Если вы собираетесь делать это много, самое время сделать из них пакет.

Ответы (35)

avatar
Adilet Usonov
13 мая 2022 в 13:39
0

Эта проблема может быть связана с Pycharm

У меня была такая же проблема при использовании Pycharm. У меня была эта структура проекта

skylake\
   backend\
      apps\
          example.py
      configuration\
          settings.py
   frontend\
      ...some_stuff

и код from configuration import settings в example.py вызвали ошибку импорта

проблема заключалась в том, что когда я открыл Pycharm, он посчитал, что skylake является корневым путем, и запустил этот код

sys.path.extend(['D:\\projects\\skylake', 'D:/projects/skylake'])

Чтобы исправить это, я просто пометил внутренний каталог как исходный корень. enter image description here

И это решило мою проблему

avatar
Daniel N.
8 апреля 2022 в 22:28
1

Если вы хотите только запустить сценарий, а не импортировать его, команда exec сделает всю работу

exec(open('/full/or/relative/path').read())
avatar
yerty
30 января 2022 в 22:25
2

Вау, я не ожидал, что потрачу на это столько времени. У меня сработало следующее:

ОС: Windows 10

Python: v3.10.0

Примечание. Так как я использую Python v3.10.0, я не использую файлы __init__.py, которые в любом случае не работали для меня.

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

Первое решение WY Hsu мне помогло. Я повторно разместил его с абсолютной ссылкой на файл для ясности:

import sys
sys.path.insert(1, 'C:\\Users\\<Your Username>\\application')
import app2.some_folder.some_file

some_file.hello_world()

Альтернативное решение: Однако это также сработало для меня:

import sys
sys.path.append( '.' )
import app2.some_folder.some_file

some_file.hello_world()

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

for path in sys.path:
    print(path)

Надеюсь, кто-то может пояснить, почему это работает в комментариях. Тем не менее, я также надеюсь, что это кому-то поможет.

avatar
Milovan Tomašević
13 июня 2021 в 19:52
7
├───root
│   ├───dir_a
│   │   ├───file_a.py
│   │   └───file_xx.py
│   ├───dir_b
│   │   ├───file_b.py
│   │   └───file_yy.py
│   ├───dir_c
│   └───dir_n

Вы можете добавить родительский каталог в PYTHONPATH, для этого вы можете использовать путь, зависящий от ОС, в «пути поиска модуля», который указан в sys.path. Таким образом, вы можете легко добавить родительский каталог следующим образом:

# file_b.py

import sys
sys.path.insert(0, '..')

from dir_a.file_a import func_name
avatar
Md Shafiul Islam
17 октября 2020 в 18:22
2

На случай, если кто-то все еще ищет решение. У меня это сработало.

Python добавляет папку, содержащую запускаемый вами скрипт, в PYTHONPATH, поэтому, если вы запустите

python application/app2/some_folder/some_file.py

В путь добавляется только папка application / app2 / some_folder (а не базовый каталог, в котором вы выполняете команду). Вместо этого запустите файл как модуль и добавьте __init__.py в каталог some_folder.

python -m application.app2.some_folder.some_file

Это добавит базовый каталог к ​​пути Python, и тогда классы будут доступны через не относительный импорт.

avatar
Neinstein
10 сентября 2020 в 09:31
2

Приведенный ниже код импортирует скрипт Python, указанный в его пути, независимо от того, где он находится, безопасным для версии Python способом:

def import_module_by_path(path):
    name = os.path.splitext(os.path.basename(path))[0]
    if sys.version_info[0] == 2:   
        # Python 2
        import imp
        return imp.load_source(name, path)
    elif sys.version_info[:2] <= (3, 4):  
        # Python 3, version <= 3.4
        from importlib.machinery import SourceFileLoader
        return SourceFileLoader(name, path).load_module()
    else:                            
        # Python 3, after 3.4
        import importlib.util
        spec = importlib.util.spec_from_file_location(name, path)
        mod = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(mod)
        return mod

Я нашел это в базе кода psutils, в строке 1042 в psutils.test.__init__.py ( самая последняя фиксация на 09.10.208г. >

Пример использования:

script = "/home/username/Documents/some_script.py"
some_module = import_module_by_path(script)
print(some_module.foo())

Важное предупреждение: модуль будет рассматриваться как модуль верхнего уровня; любой относительный импорт из родительских пакетов в нем завершится ошибкой.

Jon
30 мая 2021 в 22:50
0

Есть идеи, почему два разных метода Python3? Я попробовал оба на Python 3.6, и они оба работали, и вернули одинаковые результаты.

Jon
30 мая 2021 в 23:25
0

Также идентичные результаты на python 3.8.9. Начиная с 3.8.10 и новее, spec_from_file_location начинает сохранять корневой путь к файлу (если задан относительный путь) в объекте загрузчика , но в остальном возвращаемые данные идентичны. Также протестирован с python 3.10 - точно такое же поведение, как и 3.8.10. Оба метода работают нормально.

Neinstein
31 мая 2021 в 07:03
0

@Jon К сожалению, я не могу это комментировать, я не знаком с нюансами importlib. Это найденная собственность, и я не хотел ничего менять - решил, что у них на это есть причина. Может быть, есть какой-то другой нюанс, который не подходит для старых / новых версий.

avatar
Mustafa Kareem
8 сентября 2020 в 17:15
0

Просто используйте функцию изменения каталога из модуля ОС:

os.chdir("Here new director")

чем вы можете импортировать в обычном режиме Подробнее

avatar
kepy97
22 июля 2020 в 17:42
2

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

Например: Древовидная структура проекта

Project 
├── main.py
├── .gitignore
|
├── src
     ├────model
     |    └── user_model.py
     |────controller
          └── user_controller.py

Теперь, если вы хотите импортировать класс «UserModel» из user_model.py в файл main.py , вы можете сделать это, используя:

from src.model.user_model.py import UserModel

Кроме того, вы можете импортировать тот же класс в файл user_controller.py , используя ту же строку:

from src.model.user_model.py import UserModel

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

Richie F.
17 декабря 2020 в 20:29
0

нам нужен __init__.py в src, чтобы это произошло?

Giacomo
13 марта 2021 в 18:38
0

Это не ответ на исходный вопрос, который НЕ касался импорта из main.py, а скорее (следуя вашему примеру) из user_model.py в user_controller.py.

avatar
Mohsen Haddadi
11 июля 2020 в 18:01
13

Лучшим способом создания пакета может быть запуск и доступ к другим модулям из модуля, такого как main_module.py, в каталоге самого высокого уровня.

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

Создайте и запустите эти файлы и папки для тестирования:

 package/
    |
    |----- __init__.py (Empty file)
    |------- main_module.py (Contains: import subpackage_1.module_1)        
    |------- module_0.py (Contains: print('module_0 at parent directory, is imported'))
    |           
    |
    |------- subpackage_1/
    |           |
    |           |----- __init__.py (Empty file)
    |           |----- module_1.py (Contains: print('importing other modules from module_1...')
    |           |                             import module_0
    |           |                             import subpackage_2.module_2
    |           |                             import subpackage_1.sub_subpackage_3.module_3)
    |           |----- photo.png
    |           |
    |           |
    |           |----- sub_subpackage_3/
    |                        |
    |                        |----- __init__.py (Empty file)
    |                        |----- module_3.py (Contains: print('module_3 at sub directory, is imported')) 
    |
    |------- subpackage_2/
    |           |
    |           |----- __init__.py (Empty file)
    |           |----- module_2.py (Contains: print('module_2 at same level directory, is imported'))

Запустить main_module.py

вывод

>>>'importing other modules from module_1...'
   'module_0 at parent directory, is imported'
   'module_2 at same level directory, is imported'
   'module_3 at sub directory, is imported'

Открытие изображений и файлов, примечание:

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

Предположим, вы используете main_module.py и хотите открыть photo.png внутри module_1.py.

то, что module_1.py должно содержать:

Правильно:

image_path = 'subpackage_1/photo.png'
cv2.imread(image_path)

Неправильно:

image_path = 'photo.png'
cv2.imread(image_path)

, хотя module_1.py и photo.png находятся в одном каталоге.

avatar
picmate 涅
1 июля 2020 в 20:45
3

Обычно я создаю символическую ссылку на модуль, который хочу импортировать. Символьная ссылка гарантирует, что интерпретатор Python может найти модуль внутри текущего каталога (сценарий, в который вы импортируете другой модуль); позже, когда ваша работа закончится, вы можете удалить символическую ссылку. Кроме того, вы должны игнорировать символические ссылки в .gitignore, чтобы вы случайно не зафиксировали модули с символическими ссылками в своем репо. Такой подход позволяет вам даже успешно работать с модулями, расположенными параллельно выполняемому вами скрипту.

ln -s ~/path/to/original/module/my_module ~/symlink/inside/the/destination/directory/my_module
avatar
B Furtado
14 мая 2020 в 22:36
2

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

import sys
sys.insert(1, /path) 

НЕ работал у меня, потому что в разных модулях мне приходилось читать разные * .csv файлы, которые все находились в одном каталоге.

В конце концов, то, что сработало для меня, было не питоническим, я полагаю, а:

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

Итак:

# On top of the module, instead of on the bottom
import os
if __name__ == '__main__':
    os.chdir('/path/for/the/regularly/run/directory')
avatar
Galileoomega
13 февраля 2020 в 07:48
4

Вместо того, чтобы просто выполнять import ..., сделайте следующее:

from <MySubFolder> import <MyFile>

MyFile находится внутри MySubFolder.

avatar
WY Hsu
5 января 2020 в 09:32
11

Я несколько раз сталкивался с одним и тем же вопросом, поэтому хочу поделиться своим решением.

Версия Python: 3.X

Следующее решение предназначено для тех, кто разрабатывает ваше приложение на Python версии 3.X, поскольку Python 2 не поддерживается с 1 января 2020 года.

Структура проекта

В python 3 вам не нужен __init__.py в подкаталоге вашего проекта из-за неявных пакетов пространства имен. См. Is init .py не требуется для пакетов в Python 3.3+

Project 
├── main.py
├── .gitignore
|
├── a
|   └── file_a.py
|
└── b
    └── file_b.py

Описание проблемы

В file_b.py я хотел бы импортировать класс A в file_a.py в папке a.

Решения

# 1 Быстрый, но грязный способ

Без установки пакета, как если бы вы сейчас разрабатываете новый проект

Использование try catch для проверки наличия ошибок. Пример кода:

import sys
try:
    # The insertion index should be 1 because index 0 is this file
    sys.path.insert(1, '/absolute/path/to/folder/a')  # the type of path is string
    # because the system path already have the absolute path to folder a
    # so it can recognize file_a.py while searching 
    from file_a import A
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

# 2 Установите ваш пакет

После того, как вы установили свое приложение (в этом посте руководство по установке не включено)

Вы можете просто

try:
    from __future__ import absolute_import
    # now it can reach class A of file_a.py in folder a 
    # by relative import
    from ..a.file_a import A  
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

Удачного кодирования!

WY Hsu
5 января 2020 в 09:36
0

для получения дополнительной информации о абсолютном импорте

Giacomo
13 марта 2021 в 18:49
1

ваше первое предложенное решение сработало для меня с использованием sys.path.insert (1, '../a/'), что, по моему мнению, лучше, чем написание полного пути.

MedoAlmasry
15 марта 2021 в 11:02
0

В случае, если у кого-то есть локальный пакет, который вы хотели бы импортировать вместо системного пакета (ТОГО ИМЕЕТ ТО ЖЕ ИМЯ), используйте sys.path.insert (1, 'folder-to-grab-package-from') вместо sys. .append ('папка-получить-пакет-из')

avatar
Dextron
21 июля 2019 в 12:05
2

Вы можете использовать importlib для импорта модулей, в которые вы хотите импортировать модуль из папки, используя такую ​​строку:

import importlib

scriptName = 'Snake'

script = importlib.import_module('Scripts\\.%s' % scriptName)

В этом примере есть main.py, который представляет собой приведенный выше код, затем папка Scripts, а затем вы можете вызывать все, что вам нужно из этой папки, изменяя переменную scriptName. Затем вы можете использовать script для ссылки на этот модуль. например, если у меня есть функция с именем Hello() в модуле Snake, вы можете запустить эту функцию, выполнив следующие действия:

script.Hello()

Я тестировал это на Python 3.6

avatar
duhaime
11 июля 2019 в 19:49
2

Я работал над проектом a, который я хотел, чтобы пользователи установили через pip install a со следующим списком файлов:

.
├── setup.py
├── MANIFEST.in
└── a
    ├── __init__.py
    ├── a.py
    └── b
        ├── __init__.py
        └── b.py

setup.py

from setuptools import setup

setup (
  name='a',
  version='0.0.1',
  packages=['a'],
  package_data={
    'a': ['b/*'],
  },
)

MANIFEST.in

recursive-include b *.*

a / init .py

from __future__ import absolute_import

from a.a import cats
import a.b

a / a.py

cats = 0

a / b / init .py

from __future__ import absolute_import

from a.b.b import dogs

a / b / b.py

dogs = 1

Я установил модуль, запустив следующую команду из каталога с MANIFEST.in:

python setup.py install

Затем из совершенно другого места в моей файловой системе /moustache/armwrestle я смог запустить:

import a
dir(a)

Это подтвердило, что a.cats действительно равняется 0, а a.b.dogs действительно равняется 1, как и предполагалось.

avatar
Erick Mwazonga
1 октября 2018 в 07:00
28

Я столкнулся с той же проблемой, особенно при импорте нескольких файлов, вот как мне удалось ее преодолеть.

import os, sys

from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

from root_folder import file_name
not2qubit
23 апреля 2019 в 19:25
4

Ваш ответ был бы более полезным, если бы вы могли объяснить, чем он отличается от обычного импорта?

jwal
2 мая 2019 в 11:52
1

У меня были /path/dir1/__init__.py и /path/dir1/mod.py. Для /path/some.py из dir1.mod import func работала. Когда в /path/dir2/some.py он работал только после того, как я скопировал и вставил вышеуказанный ответ в начало файла. Не хотел редактировать свой путь, так как не все мои проекты python находятся в / path /.

avatar
wecsam
30 июля 2018 в 01:12
37

В Python 3.4 и новее вы можете импортировать напрямую из исходного файла (ссылка на документацию). Это не самое простое решение, но я включаю этот ответ для полноты картины.

Вот пример. Сначала импортируемый файл с именем foo.py:

def announce():
    print("Imported!")

Код, импортирующий файл выше, во многом вдохновлен примером из документации:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

Вывод:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Обратите внимание, что имя переменной, имя модуля и имя файла могут не совпадать. Этот код все еще работает:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

Вывод:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Программный импорт модулей был представлен в Python 3.1 и дает вам больше контроля над тем, как модули импортируются. Дополнительную информацию см. В документации.

Dan
7 января 2019 в 22:21
19

Не знаю, пытался ли хоть кто-нибудь это понять, но я думаю, что это слишком сложно.

Sincere
23 августа 2021 в 15:22
1

Это единственное решение, которое у меня сработало. У меня одно и то же имя файла в разных каталогах.

avatar
mithunpaul
27 июля 2018 в 01:27
1

Итак, я просто щелкнул правой кнопкой мыши по своей среде IDE и добавил новый folder, и мне стало интересно, почему я не могу импортировать из нее. Позже я понял, что мне нужно щелкнуть правой кнопкой мыши и создать пакет Python, а не классическую папку файловой системы. Или метод post mortem, добавляющий __init__.py (который заставляет python обрабатывать папку файловой системы как пакет), как упоминалось в других ответах. Добавляем здесь этот ответ на случай, если кто-то пошел по этому пути.

avatar
Alex Montoya
22 мая 2018 в 18:48
100

Первый импорт sys в name-file.py

 import sys

Второй добавьте путь к папке в name-file.py

sys.path.insert(0, '/the/folder/path/name-package/')

Третий Создайте в подкаталоге пустой файл с именем __ init __.py (это говорит Python, что это пакет)

  • name-file.py
  • имя-пакет
    • __ init __.py
    • name-module.py

Четвертый импортируйте модуль внутри папки в name-file.py

from name-package import name-module
Bastian
1 февраля 2019 в 09:19
9

Если имя-папка находится прямо под name-file.py, это должно работать даже без команды sys.path.insert. Таким образом, ответ оставляет вопрос, работает ли это решение, даже если папка с именем находится в произвольном месте.

Giacomo
13 марта 2021 в 18:40
0

вы говорите, что я должен жестко указать путь к скрипту? Это означает, что решение непереносимо. Также вопрос в том, как получить доступ из одной подпапки в другую. Почему бы не следовать соглашению об именах и файловой структуре исходного вопроса?

avatar
danday74
19 февраля 2018 в 03:22
53

Ответам здесь не хватает ясности, это проверено на Python 3.6

С такой структурой папок:

main.py
|
---- myfolder/myfile.py

Где myfile.py имеет содержимое:

def myfunc():
    print('hello')

Оператор импорта в main.py:

from myfolder.myfile import myfunc
myfunc()

, и это напечатает привет .

Vincent
7 марта 2018 в 17:45
12

добавление файла конфигурации ​​init .py (пустой) в мою папку сработало для меня на linux (y)

mrgloom
27 апреля 2018 в 12:40
9

@ Винсент, ты имел в виду __init__.py?

Vincent
27 апреля 2018 в 12:41
2

@mrgloom действительно

mrgloom
27 апреля 2018 в 12:47
1

Также кажется, что __init__.py больше не нужен в современном Python 3, coderhelper.com/a/39991978/1179925

Crearo Rotar
15 сентября 2018 в 18:29
3

По какой-то причине добавление __init__.py у меня не работает. Я использую Py 3.6.5 на Ubuntu 18. Он работает на Pycharm, но не с терминала.

alper
19 сентября 2018 в 15:24
0

Что, если myfunc находится в родительском каталоге? @ danday74

Alexander Rossa
23 октября 2018 в 15:38
34

Это совершенно не связано с вопросом об импорте файлов из ветви дерева файлов, отличной от текущего рабочего каталога.

Marc L.
6 июня 2019 в 14:14
8

Прекрасные диаграммы, которые явно игнорируют вопрос OP.

MattSom
2 октября 2019 в 13:53
3

Это не то, о чем спрашивал ОП.

OuuGiii
2 декабря 2019 в 20:50
1

Это вообще не ответ на вопрос.

Guilherme Araujo Lima da Silva
26 мая 2020 в 17:06
1

Единственный ответ, который сработал для меня. Я пробовал другие безуспешно. Я помещаю в подпапку пустые файлы __init__.py, но без них он работал правильно.

kağan hazal koçdemir
28 сентября 2021 в 23:03
0

а как насчет myfile.py я хочу вызвать функцию из main.py? могло быть с init?

avatar
Zectbumo
17 декабря 2017 в 08:43
30

Попробуйте относительный импорт Python:

from ...app.folder.file import func_name

Каждая ведущая точка - это еще один более высокий уровень в иерархии, начинающийся с текущего каталога.


Проблемы? Если это не работает для вас, то, вероятно, вас укусил относительный импорт многих ошибок. Прочтите ответы и комментарии для более подробной информации: Как исправить "Попытка относительного импорта в не-пакете" даже с __init__.py

Совет: имейте __init__.py на каждом уровне каталога. Вам может понадобиться python -m application.app2.some_folder.some_file (без .py), который вы запускаете из каталога верхнего уровня или этот каталог верхнего уровня находится в вашем PYTHONPATH. Уф!

secluded
17 октября 2020 в 11:19
0

Это не работает, если имя вашего каталога начинается с числа (например, import ..70_foo.test не допускается)

Camilo Martinez M.
2 июля 2021 в 20:34
1

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

avatar
schmudu
30 ноября 2017 в 00:15
14

В моем случае мне нужно было импортировать класс. Мой файл выглядел так:

# /opt/path/to/code/log_helper.py
class LogHelper:
    # stuff here

В свой основной файл я включил код через:

import sys
sys.path.append("/opt/path/to/code/")
from log_helper import LogHelper
Walter
9 сентября 2019 в 12:43
1

@ not2qubit sys не был импортирован в ответ.

avatar
Nagev
4 октября 2017 в 16:05
28

Использование sys.path.append с абсолютным путем не идеально при перемещении приложения в другие среды. Использование относительного пути не всегда работает, поскольку текущий рабочий каталог зависит от того, как был вызван сценарий.

Поскольку структура папок приложения фиксированная, мы можем использовать os.path, чтобы получить полный путь к модулю, который мы хотим импортировать. Например, если это структура:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

Допустим, вы хотите импортировать модуль манго . Вы можете сделать следующее в vanilla.py :

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

Конечно, вам не нужна переменная mango_dir .

Чтобы понять, как это работает, посмотрите этот пример интерактивного сеанса:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

И проверьте документацию os.path.

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

avatar
IOstream
12 июля 2017 в 22:10
1

Вы можете обновить оболочку Python, нажав f5, или перейти в Run-> Run Module. Таким образом, вам не нужно менять каталог, чтобы что-то прочитать из файла. Python автоматически изменит каталог. Но если вы хотите работать с разными файлами из разных каталогов в оболочке Python, вы можете изменить каталог в sys, как сказал ранее Кэмерон.

avatar
herve-guerin
18 марта 2017 в 12:36
11

Я особенный: я использую Python с Windows!

Я просто завершаю информацию: как для Windows, так и для Linux, как относительный, так и абсолютный путь работают в sys.path (мне нужны относительные пути, потому что я использую свои сценарии на нескольких ПК и в разных основных каталогах).

И при использовании Windows как \, так и / можно использовать в качестве разделителя для имен файлов, и, конечно, вы должны удвоить \ в строках Python,
несколько допустимых примеров:

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(примечание: я думаю, что / удобнее, чем \, даже если он менее «Windows-native», потому что он совместим с Linux и его проще писать и копировать в проводник Windows)

Corey Goldberg
8 февраля 2019 в 02:00
4

os.path.join ('инструменты', 'mydir')

avatar
CianB
11 февраля 2017 в 00:29
59

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

Для этого вы измените это:

from application.app.folder.file import func_name

на это:

from .application.app.folder.file import func_name

Добавляя точку, вы говорите, что ищите в этой папке папку приложения вместо того, чтобы искать в каталоге Python.

ashrasmun
26 августа 2021 в 08:49
0

ImportError: попытка относительного импорта без известного родительского пакета :(

avatar
slizb
15 ноября 2016 в 14:55
158

Когда модули находятся в параллельном расположении, как в вопросе:

application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py

Это сокращение делает один модуль видимым для другого:

import sys
sys.path.append('../')
Carl Smith
3 мая 2017 в 03:02
32

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

Rahul
17 сентября 2018 в 10:09
22

Чтобы этого избежать, мы можем получить родительский каталог файла sys.path.append(os.path.dirname(os.path.abspath(__file__)))

RCross
26 июля 2019 в 11:23
1

У меня это не сработало - мне пришлось добавить туда дополнительное имя каталога, чтобы вернуться к родительскому, чтобы запуск cli/foo.py из командной строки мог import cli.bar

towi_parallelism
27 ноября 2019 в 18:19
3

@Rahul, ваше решение не работает для интерактивных оболочек

addicted
16 декабря 2019 в 13:23
4

Если вы запустите его из корневой папки (т. Е. Из папки приложения), вы, вероятно, справитесь с sys.path.append('.'), а затем импортируете модуль с помощью from app2.some_folder.some_file import your_function. В качестве альтернативы для меня работает python3 -m app2.another_folder.another_file из корневой папки.

Amir
21 декабря 2019 в 18:47
0

Я считаю, что это самый простой способ. просто добавьте относительный путь к файлу, содержащему нужный вам модуль. в моем случае: import sys sys.append ('../ data_structure /'). модуль находится в файле внутри папки data_structure /

avatar
dsg38
16 августа 2016 в 15:24
27

У меня работал в python3 на linux

import sys  
sys.path.append(pathToFolderContainingScripts)  
from scriptName import functionName #scriptName without .py extension  
daGo
19 мая 2017 в 12:49
8

sys.path.append("/home/linux/folder/") - Убедитесь, что не используйте ярлык, например "~/folder/"

John Stud
16 июня 2020 в 17:05
1

Это самый простой ответ; работает и для Windows.

avatar
Emeeus
27 марта 2016 в 19:16
15

Это работает для меня в Windows

# some_file.py on mainApp/app2 
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file
avatar
Timothy C. Quinn
23 декабря 2015 в 15:42
7

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

Я тестировал это в Linux, но он должен работать в любой современной ОС, поддерживающей символические ссылки.

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

avatar
ChandanK
15 октября 2015 в 08:34
22

Считая application корневым каталогом для вашего проекта python, создайте пустой файл __init__.py в папках application, app и folder. Затем в вашем some_file.py внесите следующие изменения, чтобы получить определение func_name:

import sys
sys.path.insert(0, r'/from/root/directory/application')

from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
func_name()
Bolaka
13 февраля 2016 в 17:51
0

должно быть: sys.path.insert (0, r '/ from / root / directory')

avatar
Vaibhav Singh
24 ноября 2014 в 04:31
38

Насколько я знаю, добавьте файл __init__.py прямо в папку функций, которые вы хотите импортировать, и все будет.

Ax3l
20 февраля 2016 в 16:53
7

только если сценарий, который хочет включить этот другой каталог, уже находится в sys.path

herve-guerin
18 марта 2017 в 12:42
2

Я использовал sys.path.append(tools_dir) в Windows, и мне не нужно добавлять __init__.py' file in my directory tools_dir`

avatar
joey
24 февраля 2014 в 18:27
989

Все в порядке с:

from application.app.folder.file import func_name

Просто убедитесь, что folder также содержит __init__.py, это позволяет включить его как пакет. Не уверен, почему в других ответах говорится о PYTHONPATH.

msvalkon
6 марта 2014 в 13:45
64

Поскольку это не распространяется на случаи, когда необходимо изменить PYTHONPATH. Допустим, у вас есть две папки на одном уровне: A и B. A имеет __init.py__. Попробуйте импортировать что-нибудь из B в A.

zlr
15 апреля 2014 в 11:48
0

это то, что я искал, т.е. работает со стандартным локальным каталогом lib

sofly
4 ноября 2014 в 20:20
8

это отличный ответ - мне не хватало init .py для инициализации пакета. Также рекомендуется использовать передовой опыт, чтобы снизить риск столкновения пространств имен. Спасибо!

Glass
9 мая 2015 в 02:16
51

Что внутри файла init.py или __init__.py?

jay
11 мая 2015 в 23:24
63

@Xinyang Это может быть пустой файл. Само его существование говорит Python рассматривать каталог как пакет.

Ax3l
6 декабря 2015 в 13:34
1

__init__.py синтаксис более подробно описан в docs.python.org/3/tutorial/modules.html#packages и полезен, если пакет находится в системе или PYTHONPATH (вложенном) каталоге или внутри каталог самого вызывающего приложения.

Scott Prive
3 марта 2016 в 18:59
23

В настоящее время это не самый популярный ответ, но это самый правильный ответ (в большинстве случаев). Просто создайте пакет. Это не сложно. Другие ответы необходимы, потому что иногда вам могут быть запрещены определенные системные изменения (создание или изменение файла и т. Д.), Например, во время тестирования.

Sunding Wei
12 сентября 2016 в 08:42
2

Пустой init .py жизненно важен в каталоге контейнера, спасибо.

Yibo Yang
29 апреля 2017 в 07:12
11

Конечно, этот ответ предполагает, что application и app уже являются пакетами (т.е. у вас уже есть __init__.py в обоих из них). В результате добавления __init__.py также к folder, application.app.folder становится (суб) пакетом , из которого вы можете получить доступ к модулю <5277357>, символ <89357> func_name> теперь можно импортировать

dasWesen
18 июня 2017 в 12:54
59

Что бы я ни попробовал, это не сработает. Я хочу импортировать из «родственного» каталога, так что один вверх, другой вниз. У всех есть __ init __. Py, включая родительский. Это специфичный для Python 3?

borgr
24 октября 2017 в 11:57
1

@dasWesen, не думаю, что он должен сильно отличаться, но если это вам не помогает, спросите нового

dasWesen
30 октября 2017 в 11:10
2

@borgr Кажется, я обошел его тогда ... Извините, я не помню, в каком коде была эта проблема, это было слишком давно (и сейчас это не актуально для меня). Но, похоже, это обычная проблема, поэтому, если у кого-то еще есть проблема прямо сейчас, да, пожалуйста, откройте новый вопрос.

Brōtsyorfuzthrāx
22 февраля 2018 в 09:50
0

@msvalkon Если изменение пути к каталогу B не сломает вашу программу, вы можете использовать символические ссылки вместе с этим ответом, чтобы решить эту проблему. Допустим, вы находитесь в каталоге A и хотите импортировать что-то в каталог B. Добавьте __init__.py в каталог B. Создайте символическую ссылку на каталог B; поместите его в каталог A. В каталог A, import B.yourModule.

SnitchingAuggie
11 июня 2018 в 21:55
1

Есть ли решение этой проблемы сейчас? Я не могу найти способ обойти проблему, и мне очень сложно хранить все файлы одной программы в одной папке.

SMDC
20 июня 2018 в 06:31
0

Это самое простое решение

kakyo
7 июня 2019 в 10:37
6

запуск этого скрипта в командной строке с py3.7 в Windows дает мне No module named application.app.folder.file. У меня есть все init .py, включая один для родительской папки

Ashu
29 июля 2019 в 07:23
0

Если имя моей папки a_b_c и она содержит app.py, как мы можем получить к ней доступ? @joey

Minh Nghĩa
21 ноября 2019 в 15:41
2

Требуется ли по-прежнему __init__.py, учитывая неявное пространство имен пакетов?

a_m_dev
17 декабря 2019 в 06:06
3

у меня есть папка a/test.py и файл b.py на том же уровне папки. даже добавив файл __init__.py в корневую папку (как часть папки a с b.py), я не могу импортировать функцию из файла b.py внутри test.py ...

Yeahprettymuch
1 июля 2020 в 10:56
0

Как можно было бы изменить application.app.folder.file, если бы в имени папки был пробел? Кажется, нет однозначного ответа на это.

mpoletto
6 июля 2020 в 18:44
3

Звучит как шутка. Многие парни много пишут о том, что правильно, а что нет, и, наконец, кто-то говорит, что «нет ничего плохого в этом» ...

pouya
3 декабря 2020 в 17:55
1

Wish Python 4 делает что-то разумное с этой так называемой системой пакетов. Нет, сколько бы __init__.py вы ни добавили, python всегда не может найти модули.

Mohd
19 января 2021 в 17:24
1

Работает и не работает ... работает, когда я пробую from A.file import funcA на уровне Z (папка с подпапками A и B) на консоли IPython. Однако выполнение funcB внутри папки B с from A.file import funcA завершается ошибкой и выдает ошибку (ModuleNotFoundError: нет модуля с именем FashionColor). Обратите внимание, что запуск funcB изменит рабочий каталог на B. Все папки имеют init .py.

Lei_Bai
14 апреля 2021 в 17:41
1

Я использую python3, и у меня это не работает

martin36
5 августа 2021 в 09:35
1

Чтобы это работало для меня, мне пришлось добавить строки import sys и sys.path.insert(0, '') перед импортом модуля.

ashrasmun
26 августа 2021 в 08:49
0

ModuleNotFoundError: нет модуля с именем 'application' :(

avatar
Ax3l
19 февраля 2014 в 11:00
65

Я думаю, что специальным способом было бы использовать переменную среды PYTHONPATH, как описано в документации: Python2, Python3 <429736403659>

# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%

Vladimir Putin
29 июня 2014 в 22:45
0

Подождите, могу ли я заменить myScripts именем файла?

Ax3l
5 июля 2014 в 13:57
6

нет, с путем к каталогу вашего .py файла

information_interchange
13 апреля 2020 в 01:28
4

К сожалению, если вы используете Anaconda, это не сработает, поскольку PYTHONPATH на самом деле не используется внутри компании!

Ax3l
14 апреля 2020 в 08:53
1

Для (недавних) изменений в anaconda см. Этот SO для рабочих процессов и комментарии для обходных путей: coderhelper.com/questions/17386880/… Как правило, создавайте и устанавливайте небольшие пакеты вместо взлома директорий импорта.

avatar
Cameron
8 декабря 2010 в 02:12
1863

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


По умолчанию вы не можете. При импорте файла Python ищет только каталог, из которого запущен сценарий точки входа, и sys.path, который включает такие места, как каталог установки пакета (на самом деле он немного сложнее, чем этот, но это покрывает большинство случаев).

Однако вы можете добавить к пути Python во время выполнения:

# some_file.py
import sys
# insert at 1, 0 is the script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file
pseudosudo
1 сентября 2011 в 21:48
460

sys.path.append('/path/to/application/app/folder') имо чище

Cameron
2 сентября 2011 в 02:47
460

@pseudosudo: Да, это так, но вставка его в начале имеет то преимущество, что гарантирует, что путь будет найден раньше других (даже встроенных) в случае конфликтов имен.

ArtOfWarfare
31 октября 2013 в 18:54
1

Если бы только Python lists имел метод prepend, так что лучший выбор не выглядел бы некрасиво. Я понимаю причину, по которой prepend не существует (потому что у него было бы худшее время работы, чем у append), но это, похоже, спорная причина. Разве легкость чтения не должна цениться выше скорости бега?

kreativitea
3 ноября 2013 в 18:34
0

@ArtOfWarfare deques решает проблему времени выполнения, и у них есть метод appendleft. Если вам нужен список, используйте список, если вам нужна двухсторонняя очередь, используйте двухстороннюю очередь.

ArtOfWarfare
3 ноября 2013 в 20:35
9

@kreativitea - sys.path возвращает list, а не deque, и было бы глупо преобразовывать list в deque и обратно.

Ofir
20 сентября 2015 в 18:32
44

Считается ли это питоническим способом управления файлами .py в папках? Интересно ... почему по умолчанию не поддерживается? нет смысла хранить все файлы .py в одном каталоге ..

Cameron
21 сентября 2015 в 02:38
57

@Ofir: Нет, это не очень хорошее чистое питоническое решение. В общем, вы должны использовать пакеты (основанные на деревьях каталогов). Этот ответ относился к заданному вопросу и по какой-то причине продолжает набирать большое количество голосов.

AdjunctProfessorFalcon
20 августа 2016 в 23:11
2

@Cameron Что именно означает «каталог, из которого запускается сценарий точки входа»? Спасибо!

calder.ty
21 августа 2016 в 19:58
2

@ Malvin9000 Это означает, что если файл, с которым вы работаете, не является основным файлом программы. Например, вы работаете над модулем с именем foo и хотите, чтобы он импортировал пакет с именем bar. Теперь, если вы напишете другой сценарий, spam, который импортирует foo, тогда spam будет сценарием точки входа, и что, когда foo вызывает import bar, python будет искать в каталоге foo, а затем в каталоге содержащий spam.

Haseeb
10 июня 2017 в 14:55
2

У меня уже есть путь в sys.path. Когда я делаю print(sys.path), он показывает мне, что путь есть, но когда я пытаюсь импортировать, он все еще дает мне ImportError . Почему это могло происходить?

rain_
20 июня 2017 в 15:11
2

@Cameron: Не могли бы вы предоставить чистый питонический способ сделать это или ссылку на решение?

Cameron
20 июня 2017 в 16:18
1

@rain_: используйте пакеты Python, как предлагает ответ Джои.

rain_
21 июня 2017 в 09:43
2

@Cameron. У меня не работает. Я использую папку проекта. с некоторыми вложенными папками на нем. Одна из этих подпапок содержит init .py и files.py с функциями. Из любого файла в подпапке, которую я использую: from functions_folder.functions import *, и это просто не работает.

Andreas Forslöw
24 сентября 2019 в 19:41
0

@GabrielStaples да, он работает с относительными путями.

Andreas Forslöw
24 сентября 2019 в 19:48
0

Еще одна вещь, на которую стоит обратить внимание в отношении этого подхода, который делает его непитоническим, заключается в том, что вы не можете иметь то же имя для любого из ваших модулей sys.path, что и один из ваших локальных модулей. Т.е. вы не можете импортировать sys/path/module.py в свой current/package/main.py, если current/package/main.py импортирует current/package/module.py. Другими словами, все импортируемые модули должны иметь уникальные имена.

jpmc26
18 октября 2019 в 03:15
1

Ужасный совет даже по этому конкретному вопросу. Намного лучше вместо этого обновить PYTHONPATH из командной строки.

alex
30 января 2020 в 16:58
3

Это ужасно. Что, если я решу провести рефакторинг и переместить свой пакет в другой каталог? Нужно ли мне найти все файлы, использующие этот пакет, и обновить эту инструкцию sys.path.insert?

McLawrence
23 апреля 2020 в 10:19
0

Важно отметить, что даже если вы используете что-то вроде os.path.abspath, псевдонимы типа ~ для вашего домашнего каталога не заменяются.

Steve Scott
12 июня 2020 в 17:52
1

Интересно. Он принимает только путь в виде строки. Он не принимает объект пути.

Hi-Angel
27 июля 2020 в 09:43
1

У меня не работает. У меня есть файл foo, который я импортирую, который, в свою очередь, импортирует файл conftest, который находится в файле ../conftest.py. Поэтому я делаю sys.path.append(tests_dir), где tests_dir я пытался быть как ../, так и абсолютным путем. Однако после выполнения import foo я все еще получаю сообщение «Нет теста модуля с именем 'conftest'».

theX
5 августа 2020 в 01:19
0

@ Hi-Angel, это решит вашу проблему ?: coderhelper.com/questions/62886769/…

Hi-Angel
5 августа 2020 в 06:19
0

@theX спасибо, я должен попробовать. Пока я работал над этим, помещая скрипт в другой каталог.

Rogério Oliveira
26 августа 2020 в 15:11
0

Подход Python, связанный с импортом модулей, еще нуждается в улучшении. Это может быть проще и понятнее, например, JavaScript, C #, Java, C ++ и так далее.

Shalomi90
7 сентября 2020 в 15:13
0

Привет, ребята, у меня такая же проблема, но решение не работает. путь в скобках подчеркнут и не может быть найден. Что я могу сделать? Это правильный путь

Isi
25 сентября 2020 в 08:34
1

@ Shalomi11 В Windows я рекомендую sys.path.insert(1, os.path.abspath('/path/to/application/app/folder')), поскольку в приведенных выше обозначениях косая черта не такая, как должна быть в Windows. (Вы можете проверить это, если поставите точку останова после этой строки, а затем в режиме отладки отметьте «sys.path»)

young_souvlaki
26 марта 2021 в 17:59
1

@Cameron Можете ли вы дать ссылку на описанное вами решение Python, включающее пакеты и деревья каталогов?

HAL9000
21 августа 2021 в 07:36
0

можно ли добавить все эти «пользовательские» пакеты в общий файл Python, или вам нужно добавить эту строку во все файлы .py, которые должны импортировать эти пользовательские модули?