web-dev-qa-db-fra.com

Importer des fichiers depuis différents dossiers

J'ai la structure de dossier suivante.

application/app/folder/file.py

et je veux importer des fonctions de file.py dans un autre fichier Python qui réside dans

application/app2/some_folder/some_file.py

J'ai essayé

from application.app.folder.file import func_name

et quelques autres tentatives mais je n'ai pas réussi jusqu'ici à importer correctement. Comment puis-je faire ceci?

1099
Ivan

Par défaut, vous ne pouvez pas. Lors de l'importation d'un fichier, Python ne recherche que le répertoire en cours, le répertoire à partir duquel le script de point d'entrée est exécuté, et sys.path, qui comprend des emplacements tels que le répertoire d'installation du paquet (c'est en fait un peu plus complexe que cela, mais cela couvre la plupart des cas).

Cependant, vous pouvez ajouter au chemin Python au moment de l'exécution:

# 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
1172
Cameron

Rien à redire avec:

from application.app.folder.file import func_name

Assurez-vous simplement que folder contient également un __init__.py, cela lui permet d'être inclus dans un package. Vous ne savez pas pourquoi les autres réponses parlent de PYTHONPATH.

581
joey

Lorsque les modules sont dans des emplacements parallèles, comme dans la question:

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

Ce raccourci rend un module visible à l'autre:

import sys
sys.path.append('../')
76
slizb

Je pense qu'un moyen ad-hoc serait d'utiliser la variable d'environnement PYTHONPATH comme décrit dans la documentation: Python2 , Python

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

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

Premier système d'importation

 import sys

Second ajoute le chemin du dossier

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

Troisième Créez un fichier vierge appelé __ init __.py dans votre sous-répertoire (cela indique que Python est un module)

  • nom-fichier.py
    • nom-dossier
      • __ init __.py
      • nom-module.py

Quatrième importer le module dans le dossier

from name-folder import name-module
36
Alex Montoya

Votre problème est que Python cherche dans le répertoire Python ce fichier et ne le trouve pas. Vous devez spécifier que vous parlez du répertoire dans lequel vous vous trouvez et non du Python.

Pour ce faire, vous changez ceci:

from application.app.folder.file import func_name

pour ça:

from .application.app.folder.file import func_name

En ajoutant le point que vous indiquez, recherchez dans le dossier de l'application le dossier de l'application plutôt que dans le répertoire Python.

32
CianB

Les réponses ici manquent de clarté, ceci est testé sur Python 3.6

Avec cette structure de dossier:

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

myfile.py a le contenu:

def myfunc():
    print('hello')

L'instruction d'importation dans main.py est la suivante:

from myfolder.myfile import myfunc
myfunc()

et cela affichera bonjour .

32
danday74

De ce que je sais, ajouter un fichier __init__.py directement dans le dossier des fonctions que vous souhaitez importer fera le travail.

29
Vaibhav Singh

En considérant application comme répertoire racine de votre projet python, créez un fichier __init__.py vide dans les dossiers application, app et folder. Ensuite, dans votre some_file.py apportez les modifications comme suit pour obtenir la définition de 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()
19
ChandanK

J'ai été confronté au même défi, en particulier lors de l'importation de plusieurs fichiers. C'est ainsi que j'ai réussi à le surmonter.

import os, sys

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

from root_folder import file_name
17
Erick Mwazonga

A travaillé pour moi en python3 sur linux

import sys  
sys.path.append(pathToFolderContainingScripts)  
from scriptName import functionName #scriptName without .py extension  
17
dsg38

Dans Python 3.4 et versions ultérieures, vous pouvez importer directement à partir d'un fichier source (lien vers la documentation) . Ce n'est pas la solution la plus simple, mais j'inclus cette réponse par souci d'exhaustivité.

Voici un exemple. Tout d’abord, le fichier à importer, nommé foo.py:

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

Le code qui importe le fichier ci-dessus, largement inspiré de l'exemple de la documentation:

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 __== "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

Le résultat:

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

Notez que le nom de la variable, le nom du module et le nom du fichier ne doivent pas nécessairement correspondre. Ce code fonctionne toujours:

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 __== "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

Le résultat:

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

L'importation de modules par programme a été introduite dans Python 3.1 et vous donne davantage de contrôle sur la manière dont les modules sont importés. Reportez-vous à la documentation pour plus d'informations.

15
wecsam

Essayez les importations relatives de Python:

from ...app.folder.file import func_name

Chaque point en tête est un autre niveau supérieur de la hiérarchie commençant par le répertoire actuel.


Problèmes? Si cela ne fonctionne pas pour vous, alors vous êtes probablement pris au dépourvu par les nombreuses importations relatives de Gotcha. Lisez les réponses et les commentaires pour plus de détails: Comment réparer "Tentative d'importation relative dans un non-package" même avec __init __. Py

Astuce: ayez __init__.py à chaque niveau de répertoire. Vous aurez peut-être besoin de python -m application.app2.some_folder.some_file (en laissant de côté .py) que vous exécutez à partir du répertoire de niveau supérieur ou que ce répertoire de niveau supérieur se trouve dans votre PYTHONPATH. Ouf!

15
Zectbumo

Cela fonctionne pour moi sur Windows

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

import some_file
12
Emeeus

L'utilisation de sys.path.append avec un chemin absolu n'est pas idéale lorsque vous déplacez l'application vers d'autres environnements. L'utilisation d'un chemin relatif ne fonctionnera pas toujours car le répertoire de travail en cours dépend de la façon dont le script a été appelé.

Puisque la structure du dossier de l'application est fixe, nous pouvons utiliser os.path pour obtenir le chemin complet du module que nous souhaitons importer. Par exemple, s'il s'agit de la structure:

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

Et disons que vous voulez importer le module "mangue". Vous pouvez faire ce qui suit dans 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

Bien sûr, vous n’avez pas besoin de la variable mango_dir.

Pour comprendre comment cela fonctionne, regardez cet exemple de session interactive:

>>> 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'
>>> 

Et consultez la documentation os.path .

12
Nagev

Je suis assez spécial: j'utilise Python avec Windows!

Je viens juste de compléter les informations: pour Windows et Linux, les chemins relatifs et absolus fonctionnent dans sys.path (j'ai besoin de chemins relatifs, car j'utilise mes scripts sur plusieurs PC et dans différents répertoires principaux).

Et lorsque vous utilisez Windows, \ et / peuvent être utilisés comme séparateur de noms de fichiers et vous devez bien entendu doubler \ dans Python chaînes,
Quelques exemples valables:

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

(note: je pense que / est plus pratique que \, même s'il est moins 'natif de Windows' car compatible avec Linux, il est plus simple d'écrire et de copier dans l'explorateur Windows)

9
geekobi

Si le but du chargement d'un module à partir d'un chemin spécifique est de vous aider lors du développement d'un module personnalisé, vous pouvez créer un lien symbolique dans le même dossier du script de test qui pointe vers la racine du module personnalisé. Cette référence de module aura la priorité sur tout autre module installé du même nom pour tout script exécuté dans ce dossier.

J'ai testé cela sous Linux, mais cela devrait fonctionner dans tout système d'exploitation moderne prenant en charge les liens symboliques.

Un avantage de cette approche est que vous pouvez pointer sur un module qui se trouve dans votre propre copie de travail de branche SVC locale, ce qui simplifie grandement le temps de cycle de développement et réduit les modes de défaillance de la gestion des différentes versions du module.

6
Timothy C. Quinn

Dans mon cas, j'avais une classe à importer. Mon fichier ressemblait à ceci:

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

Dans mon fichier principal, j'ai inclus le code via:

path.append("/opt/path/to/code/")
from log_helper import LogHelper
2
schmudu

Je travaillais sur le projet a que je voulais que les utilisateurs installent via pip install a avec la liste de fichiers suivante:

.
├── 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

J'ai installé le module en lançant ce qui suit à partir du répertoire avec MANIFEST.in:

python setup.py install

Ensuite, à partir d’un emplacement totalement différent sur mon système de fichiers /moustache/armwrestle, j’ai pu exécuter:

import a
dir(a)

Ce qui a confirmé que a.cats était bien égal à 0 et a.b.dogs était égal à 1, comme prévu.

1
duhaime

Vous pouvez actualiser le shell Python en appuyant sur f5 ou aller à Exécuter-> Exécuter le module. De cette façon, vous n'avez pas à changer de répertoire pour lire quelque chose dans le fichier. Python changera automatiquement le répertoire. Mais si vous souhaitez utiliser différents fichiers provenant de différents répertoires dans le shell Python, vous pouvez modifier le répertoire dans sys, comme l'a dit Cameron plus tôt.

1
IOstream

Donc, je venais juste de cliquer sur mon IDE et d'ajouter un nouveau folder et je me demandais pourquoi je ne pouvais pas importer à partir de celui-ci. Plus tard, j'ai réalisé que je devais faire un clic droit et créer un package Python, et non un dossier de système de fichiers classique. Ou une méthode post-mortem ajoutant un __init__.py (ce qui oblige python à traiter le dossier du système de fichiers comme un paquet), comme indiqué dans d'autres réponses. Ajout de cette réponse ici juste au cas où quelqu'un irait par cette voie.

1
mithunpaul

Vous pouvez utiliser importlib pour importer des modules dans lesquels vous souhaitez importer un module depuis un dossier en utilisant une chaîne telle que:

import importlib

scriptName = 'Snake'

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

Cet exemple a un fichier main.py qui est le code ci-dessus, puis un dossier appelé Scripts. Vous pouvez ensuite appeler tout ce dont vous avez besoin depuis ce dossier en modifiant la variable scriptName. Vous pouvez ensuite utiliser script pour faire référence à ce module. Par exemple, si j'ai une fonction appelée Hello() dans le module Snake, vous pouvez exécuter cette fonction de la manière suivante:

script.Hello()

J'ai testé cela dans Python 3.6

1
Dextron