web-dev-qa-db-fra.com

Importer un module depuis un chemin relatif

Comment importer un module Python étant donné son chemin relatif?

Par exemple, si dirFoo contient Foo.py et dirBar, et dirBar contient Bar.py, comment puis-je importer Bar.py dans Foo.py ?

Voici une représentation visuelle:

dirFoo\
    Foo.py
    dirBar\
        Bar.py

Foo souhaite inclure Bar, mais la restructuration de la hiérarchie des dossiers n'est pas une option.

738
Jude Allred

En supposant que vos deux répertoires sont de véritables packages Python (contiennent le fichier __init__.py], voici une solution sûre pour l'inclusion de modules par rapport à l'emplacement du script.

Je suppose que vous voulez faire cela, car vous devez inclure un ensemble de modules avec votre script. J'utilise ceci en production dans plusieurs produits et fonctionne dans de nombreux scénarios spéciaux tels que: les scripts appelés depuis un autre répertoire ou exécutés avec python execute au lieu d'ouvrir un nouvel interpréteur.

 import os, sys, inspect
 # realpath() will make your script run, even if you symlink it :)
 cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
 if cmd_folder not in sys.path:
     sys.path.insert(0, cmd_folder)

 # Use this if you want to include modules from a subfolder
 cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
 if cmd_subfolder not in sys.path:
     sys.path.insert(0, cmd_subfolder)

 # Info:
 # cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
 # __file__ fails if the script is called in different ways on Windows.
 # __file__ fails if someone does os.chdir() before.
 # sys.argv[0] also fails, because it doesn't not always contains the path.

En prime, cette approche vous permet de forcer Python à utiliser votre module à la place de ceux installés sur le système.

Attention! Je ne sais pas vraiment ce qui se passe lorsque le module actuel est dans un fichier Egg. Cela échoue probablement aussi.

327
sorin

Assurez-vous que dirBar a le fichier __init__.py - cela transforme un répertoire dans un package Python.

323
S.Lott

Vous pouvez également ajouter le sous-répertoire à votre chemin Python afin qu'il soit importé en tant que script normal.

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
255
Andrew Cox
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)

import mymodule
114
lefakir

Il suffit de faire des choses simples pour importer le fichier .py à partir d’un dossier différent.

Disons que vous avez un répertoire comme:

lib/abc.py

Il suffit ensuite de garder un fichier vide dans le dossier lib nommé

__init__.py

Et puis utiliser

from lib.abc import <Your Module name>

Conservez le fichier __init__.py dans chaque dossier de la hiérarchie du module d'importation.

100
Deepak 'Kaseriya'

Si vous structurez votre projet de cette façon:

src\
  __init__.py
  main.py
  dirFoo\
    __init__.py
    Foo.py
  dirBar\
    __init__.py
    Bar.py

Ensuite, à partir de Foo.py, vous devriez pouvoir faire:

import dirFoo.Foo

Ou:

from dirFoo.Foo import FooObject

Selon le commentaire de Tom, cela nécessite que le dossier src soit accessible via site_packages ou votre chemin de recherche. De plus, comme il le mentionne, __init__.py est importé implicitement lors de la première importation d'un module dans ce paquet/répertoire. Typiquement, __init__.py est simplement un fichier vide.

79
bouvard

La méthode la plus simple consiste à utiliser sys.path.append ().

Cependant, vous pouvez également être intéressé par le module imp . Il donne accès aux fonctions d'importation internes.

# mod_name is the filename without the .py/.pyc extention
py_mod = imp.load_source(mod_name,filename_path) # Loads .py file
py_mod = imp.load_compiled(mod_name,filename_path) # Loads .pyc file 

Cela peut être utilisé pour charger des modules de manière dynamique lorsque vous ne connaissez pas le nom d'un module.

J'ai déjà utilisé cela par le passé pour créer une interface de type plugin vers une application, dans laquelle l'utilisateur écrivait un script avec des fonctions spécifiques à l'application et déposait simplement son script dans un répertoire spécifique.

En outre, ces fonctions peuvent être utiles:

imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)
44
monkut

Voici le PEP pertinent:

http://www.python.org/dev/peps/pep-0328/

En particulier, supposer que dirFoo est un répertoire situé en amont de dirBar ...

Dans dirFoo\Foo.py:

from ..dirBar import Bar
43
Peter Crabtree

Le moyen le plus simple, sans aucune modification de votre script, consiste à définir la variable d’environnement PYTHONPATH. Parce que sys.path est initialisé à partir de ces emplacements:

  1. Le répertoire contenant le script d'entrée (ou le répertoire actuel).
  2. PYTHONPATH (liste de noms de répertoires, avec la même syntaxe que la variable shell PATH).
  3. La valeur par défaut dépendante de l'installation.

Il suffit de courir:

export PYTHONPATH=/absolute/path/to/your/module

Sys.path contiendra le chemin ci-dessus, comme indiqué ci-dessous:

print sys.path

['', '/absolute/path/to/your/module', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client', '/usr/lib/python2.7/dist-packages/ubuntuone-client', '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel', '/usr/lib/python2.7/dist-packages/ubuntuone-couch', '/usr/lib/python2.7/dist-packages/ubuntuone-installer', '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']
22
James Gan

A mon avis, le meilleur choix est de mettre __ init __. Py dans le dossier et d’appeler le fichier avec

from dirBar.Bar import *

Il n'est pas recommandé d'utiliser sys.path.append (), car quelque chose pourrait mal tourner si vous utilisez le même nom de fichier que le package python existant. Je n'ai pas testé cela, mais ce sera ambigu.

12
jhana

Le moyen le plus rapide pour les utilisateurs de Linux

Si vous vous contentez de bricoler et que vous ne vous préoccupez pas des problèmes de déploiement, vous pouvez utiliser un lien symbolique (en supposant que votre système de fichiers le supporte) pour rendre le module ou le package directement visible dans le dossier du module demandeur.

ln -s (path)/module_name.py

ou

ln -s (path)/package_name

Remarque: Un "module" est un fichier avec une extension .py et un "package" est un dossier contenant le fichier __init__.py (qui peut être un fichier vide). Du point de vue de l'utilisation, les modules et les packages sont identiques - les deux exposent leurs "définitions et instructions" contenues dans la requête, à l'aide de la commande import.

Voir: http://docs.python.org/2/tutorial/modules.html

11
nobar
from .dirBar import Bar

au lieu de:

from dirBar import Bar

juste au cas où il pourrait y avoir un autre dirBar installé et confondre un lecteur foo.py.

9
jgomo3

Pour ce cas, importer Bar.py dans Foo.py, tout d’abord, je transformerais ces dossiers en Python paquets comme ceci:

dirFoo\
    __init__.py
    Foo.py
    dirBar\
        __init__.py
        Bar.py

Ensuite, je le ferais comme ceci dans Foo.py:

from .dirBar import Bar

Si je voulais que l'espace de noms ressemble à Bar .peu importe, ou

from . import dirBar

Si je voulais le namespacing dirBar.Bar .peu importe. Ce second cas est utile si vous avez plus de modules sous le paquet dirBar.

8
Al Conrad

Ajoutez un fichier __ init __. Py:

dirFoo\
    Foo.py
    dirBar\
        __init__.py
        Bar.py

Ajoutez ensuite ce code au début de Foo.py:

import sys
sys.path.append('dirBar')
import Bar
6
Josh

Exemple relatif sys.path:

# /lib/my_module.py
# /src/test.py


if __== '__main__' and __package__ is None:
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')))
import my_module

Basé sur this réponse.

5
Der_Meister

Comme vous le mentionnez, vous souhaitez généralement avoir accès à un dossier contenant vos modules par rapport à l'emplacement d'exécution de votre script principal. Vous ne devez donc les importer que.

Solution:

J'ai le script dans D:/Books/MyBooks.py et quelques modules (comme oldies.py). J'ai besoin d'importer du sous-répertoire D:/Books/includes:

import sys,site
site.addsitedir(sys.path[0] + '\\includes')
print (sys.path)  # Just verify it is there
import oldies

Placez une print('done') dans oldies.py afin de vérifier que tout se passe bien. Cela fonctionne toujours parce que, par le Python definition sys.path initialisé au démarrage du programme, le premier élément de cette liste, path[0], est le répertoire contenant le script utilisé pour appeler l'interprète Python.

Si le répertoire de script n'est pas disponible (par exemple, si l'interpréteur est appelé de manière interactive ou si le script est lu à partir de l'entrée standard), path[0] est la chaîne vide, qui dirige Python vers les modules de recherche dans le répertoire. répertoire actuel en premier. Notez que le répertoire de script est inséré avant les entrées insérées à la suite de PYTHONPATH.

4
Avenida Gez

Une autre solution consisterait à installer le package py-require , puis à utiliser les éléments suivants dans Foo.py

import require
Bar = require('./dirBar/Bar')
3
Niklas R

Vous pouvez simplement utiliser: from Desktop.filename import something

Exemple:

étant donné que le fichier s'appelle test.py dans le répertoire Users/user/Desktop, il importera tout.

le code:

from Desktop.test import *

Mais assurez-vous de créer un fichier vide appelé "__init__.py" dans ce répertoire

3
0x1996

Voici un moyen d'importer un fichier d'un niveau supérieur en utilisant le chemin relatif.

Fondamentalement, déplacez simplement le répertoire de travail d'un niveau (ou de tout emplacement relatif), ajoutez-le à votre chemin, puis déplacez le répertoire de travail à son point de départ.

#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path =  os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)
2
Justin Muller

Regardez le module pkgutil de la bibliothèque standard. Cela peut vous aider à faire ce que vous voulez.

2
Mihail Mihaylov

Je n’ai pas d’expérience du python. Par conséquent, s’il ya quelque chose qui cloche, dites-le-moi simplement. Si votre hiérarchie de fichiers est organisée comme ceci:

project\
    module_1.py 
    module_2.py

module_1.py définit une fonction appelée func_1(), module_2.py:

from module_1 import func_1

def func_2():
    func_1()

if __== '__main__':
    func_2()

et vous lancez python module_2.py dans cmd, il exécutera ce que func_1() définit. C'est généralement comme cela que nous importons les mêmes fichiers de hiérarchie. Mais lorsque vous écrivez from .module_1 import func_1 dans module_2.py, python, l'interprète dira No module named '__main__.module_1'; '__main__' is not a package. Donc, pour résoudre ce problème, nous conservons simplement les modifications que nous venons de faire, nous déplaçons les deux modules dans un package, puis nous appelons un troisième module en tant qu'appelant pour exécuter 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 __== '__main__':
    func_3()

Mais la raison pour laquelle nous ajoutons un . avant module_1 dans module_2.py est que si nous ne le faisons pas et exécutons main.py, python l'interprète dira No module named 'module_1', c'est un peu compliqué, module_1.py est juste à côté de module_2.py. Maintenant, je laisse func_1() dans module_1.py faire quelque chose:

def func_1():
    print(__name__)

que __name__ enregistre qui appelle func_1. Maintenant, nous conservons le . avant module_1, exécutons main.py, il imprimera package_1.module_1 et non module_1. Il indique que celui qui appelle func_1() est dans la même hiérarchie que main.py, le . implique que module_1 est dans la même hiérarchie que module_2.py. Donc, s'il n'y a pas de point, main.py reconnaîtra module_1 à la même hiérarchie que lui-même, il pourra reconnaître package_1, mais pas ce qu'il "sous".

Rendons maintenant un peu compliqué. Vous avez un config.ini et un module définit une fonction pour le lire dans la même hiérarchie que 'main.py'.

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

Et pour une raison inévitable, vous devez l'appeler avec module_2.py, il doit donc importer depuis la hiérarchie supérieure .module_2.py:

 import ..config
 pass

Deux points signifie une importation depuis la hiérarchie supérieure (trois points d’accès supérieur à supérieur, etc.). Maintenant, nous lançons main.py, l'interprète dira: ValueError:attempted relative import beyond top-level package. Le "paquetage de niveau supérieur" ici est main.py. Juste parce que config.py est à côté de main.py, ils sont dans la même hiérarchie, config.py n'est pas "sous" main.py, ou il n'est pas "guidé" par main.py, donc c'est au-delà de main.py. Pour résoudre ce problème, le moyen le plus simple est:

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

Je pense que cela coïncide avec le principe d’arrangement de la hiérarchie des fichiers de projet. Vous devez arranger les modules avec des fonctions différentes dans des dossiers différents, tout en laissant un interlocuteur principal à l’extérieur, et vous pouvez importer ce que vous voulez.

0