Importer à partir d'un chemin relatif en Python

Réponses:

140

EDIT Nov 2014 (3 ans plus tard):

Python 2.6 et 3.x prend en charge les importations relatives appropriées, où vous pouvez éviter de faire quoi que ce soit de piraté. Avec cette méthode, vous savez que vous obtenez une importation relative plutôt qu'une importation absolue . Le '..' signifie, allez dans le répertoire au-dessus de moi:

from ..Common import Common

En guise de mise en garde, cela ne fonctionnera que si vous exécutez votre python en tant que module, depuis l' extérieur du package. Par exemple:

python -m Proj

Voie piratée originale

Cette méthode est encore couramment utilisée dans certaines situations, où vous n'installez jamais votre paquet. Par exemple, il est populaire auprès des utilisateurs de Django.

Vous pouvez ajouter Common / à votre sys.path (la liste des chemins que python regarde pour importer des choses):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) vous donne simplement le répertoire dans lequel se trouve votre fichier python actuel, puis nous naviguons vers le répertoire «Common /» et importons le module «Common».

Dave
la source
2
Ne modifiez pas manuellement le chemin des modules python, cela peut être uniquement pour des hacks rapides. Apprendre la gestion de paquets Python à l'aide de distutils, setuptools, etc. est généralement une compétence requise qui résoudra des problèmes comme celui-là.
Sascha Gottfried
1
@SaschaGottfried est totalement d'accord, bien que si vous ne créez pas de paquet distribuable, cela n'aura probablement pas d'importance. Par exemple, dans Django, vous n'installez jamais vraiment votre application avec distutils, donc la méthode ci-dessus est un hack facile. Mais de toute façon, j'ai édité la réponse avec ce que je ferais ces jours-ci.
Dave
32
Merci d'avoir répondu à la question au lieu de prêcher sur la bonne technique. Il existe de nombreuses bonnes raisons de faire des importations relatives.
shrewmouse
comment monterais-tu plus d'un niveau?
jxramos
10
pour monter d'un niveau de plus, utilisez un point supplémentaire pour chaque niveau. @jxramos ex: from ...myfileva à../../myfile
WattsInABox
10

Assez drôle, un même problème que je viens de rencontrer, et j'obtiens ce travail de la manière suivante:

en combinant avec la commande linux ln, nous pouvons rendre les choses beaucoup plus simples:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

Et maintenant si vous souhaitez importer some_stuff depuis un fichier: Proj/Common/Common.pydans votre fichier Proj/Client/Client.py:, comme ceci:

# in Proj/Client/Client.py
from Common.Common import some_stuff

Et, la même chose s'applique à Proj/Server, Fonctionne également pour le setup.pyprocessus, une même question discutée ici , espérons que cela aide!

Jacoolee
la source
10

Ne faites pas d'importation relative.

À partir de PEP8 :

Les importations relatives pour les importations intra-colis sont fortement découragées.

Mettez tout votre code dans un super package (c'est-à-dire "myapp") et utilisez des sous-packages pour le client, le serveur et le code commun.

Mise à jour: " Python 2.6 et 3.x prend en charge les importations relatives appropriées (...) ". Voir les réponses de Dave pour plus de détails.

Michał Šrajer
la source
1
Imaginez que vous ajoutez du code à la fin du client et du serveur après la if __name__ == "__main__":ligne « ». Autrement dit, vous voulez pouvoir les utiliser en tant que scripts autonomes. Comment le faire correctement? Je pense que c'est un cas d'utilisation parfaitement courant qui devrait être pris en charge. Pourquoi est-ce découragé?
Jabba
83
Je suis surpris que "Ne le fais pas" soit la réponse acceptée à une question "comment faire ..." (enfin, sauf pour Rails <g>.) Il y a des raisons occasionnelles de faire cela. J'utilise une solution similaire à ce que suggère Dave.
Tom Wilson
1
@TomWilson: Ce n'est pas une réponse pure "ne le faites pas". Il y a "faites-le de cette façon" ci-dessous.
Michał Šrajer
2
Quelqu'un devrait dire aux gars de Numpy! Ils utilisent une tonne d'importations relatives!
Austin A
12
Cette réponse ne s'applique pas aux versions actuelles de Python. La partie citée ne se trouve plus dans PEP 8. Aujourd'hui, elle se lit comme suit: "les importations relatives explicites sont une alternative acceptable aux importations absolues, en particulier lorsqu'il s'agit de mises en page complexes de packages où l'utilisation d'importations absolues serait inutilement verbeuse"
moooeeeep
8

Faire une importation relative est absolument OK! Voici ce que fait le petit moi:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py
Gary Beardsley
la source
1
Mais vous feriez mieux de savoir où sys.argv [0] pointe réellement - ce n'est (probablement) pas le répertoire dans lequel vous vous trouviez lorsque vous avez démarré python.
CarlH
C'est un hack rapide, avec beaucoup d'embûches. Mais la question n'était même pas meilleure.
Sascha Gottfried
1
Ceci est clairement écrit, mais le hack original dans la réponse de Dave est meilleur car il utilise __file__pour obtenir la bonne relation à partir du fichier actuel
John Neuhaus
4

La méthode d'importation par défaut est déjà "relative", à partir du PYTHONPATH. Le PYTHONPATH est par défaut, vers certaines bibliothèques système avec le dossier du fichier source d'origine. Si vous exécutez avec -m pour exécuter un module, le répertoire actuel est ajouté au PYTHONPATH. Donc, si le point d'entrée de votre programme se trouve à l'intérieur de Proj, utilisezimport Common.Common devrait fonctionner à la fois dans Server.py et Client.py.

Ne faites pas d'importation relative. Cela ne fonctionnera pas comme vous le souhaitez.

Jonathan Sternberg
la source
1
Si cela est vrai, pourquoi les principales réponses ne le disent-elles pas? Cela fonctionnera-t-il ou non?
Anonyme le