Question

Imaginez cette structure de répertoire:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

Je code mod1 et je dois importer quelque chose à partir de mod2 . Comment devrais-je le faire?

J'ai essayé dans ..s2 import2 mod2 mais je reçois un "Importation relative tentée dans un non-package".

J'ai cherché sur Google mais n'ai trouvé que la "manipulation < sys.path ". hacks. N'y a-t-il pas un moyen propre?

Modifier: tous mes __ init __. py sont actuellement vides

Edit2: J'essaie de faire cela car sub2 contient des classes qui sont partagées entre plusieurs sous-packages ( sub1 , subX , etc.).

Edit3: Le comportement recherché est identique à celui décrit dans PEP 366. (merci John B)

Était-ce utile?

La solution

Tout le monde semble vouloir vous dire ce que vous devriez faire plutôt que de simplement répondre à la question.

Le problème est que vous exécutez le module en tant que '__main__' en transmettant le mod1.py en tant qu'argument à l'interpréteur.

De PEP 328 :

  

Les importations relatives utilisent l'attribut __name__ du module pour déterminer la position de ce module dans la hiérarchie des packages. Si le nom du module ne contient aucune information sur le package (par exemple, il est défini sur '__main__'), les importations relatives sont résolues comme si le module était un module de niveau supérieur, quel que soit l'emplacement du module dans le système de fichiers.

Dans Python 2.6, ils ajoutaient la possibilité de référencer des modules par rapport au module principal. Le PEP 366 décrit ce changement.

Mise à jour : selon Nick Coghlan, l'alternative recommandée consiste à exécuter le module à l'intérieur du package à l'aide du commutateur -m.

Autres conseils

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. Vous exécutez python main.py .
  2. main.py fait: importer app.package_a.module_a
  3. module_a.py importe-t-il app.package_b.module_b

Alternativement, 2 ou 3 pourraient utiliser: depuis app.package_a import module_a

Cela fonctionnera tant que vous aurez app dans votre PYTHONPATH. main.py pourrait être n'importe où alors.

Vous écrivez donc un setup.py pour copier (installer) l'intégralité du package et des sous-packages de l'application dans les dossiers python du système cible, et main.py dans le script du système cible dossiers.

Voici la solution qui fonctionne pour moi:

Je fais les importations relatives en tant que à partir de ..sub2 import mod2 et puis, si je veux exécuter mod1.py , je vais dans le répertoire parent de app et exécute le module à l'aide du commutateur python -m en tant que python - m app.sup1.mod1 .

La véritable raison de ce problème avec les importations relatives est que les importations relatives fonctionnent en prenant la propriété __ name __ du module. Si le module est exécuté directement, __ nom __ est défini sur __ main __ et ne contient aucune information sur la structure du package. Et c’est la raison pour laquelle python se plaint de l’erreur relative à l’importation dans un non-package .

Ainsi, en utilisant le commutateur -m, vous fournissez les informations sur la structure du package à python, grâce auxquelles il peut résoudre les importations relatives.

J'ai rencontré ce problème plusieurs fois lors de l'importation relative. Et, après avoir lu toutes les réponses précédentes, je n’étais toujours pas en mesure de trouver une solution propre, sans avoir besoin de mettre du code passe-partout dans tous les fichiers. (Bien que certains commentaires aient été vraiment utiles, merci à @ncoghlan et @XiongChiamiov)

J'espère que cela aidera quelqu'un qui se bat avec le problème des importations relatives, car passer par PEP n'est vraiment pas amusant.

"Guido considère l’exécution de scripts dans un package comme un anti-motif". (rejeté PEP-3122 )

J'ai passé beaucoup de temps à essayer de trouver une solution, à lire des billets sur Stack Overflow et à me dire "il doit y avoir une meilleure façon!". On dirait qu'il n'y en a pas.

Ceci est résolu à 100%:

  • app /
    • main.py
  • paramètres /
    • local_setings.py

Importer les paramètres / local_setting.py dans app / main.py:

main.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')
def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

J'utilise cet extrait pour importer des modules à partir de chemins d'accès, espérons que cela aidera

explication de la réponse de nosklo avec des exemples

remarque: tous les fichiers __ init __. py sont vides.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app / package_a / fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app / package_b / fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

si vous exécutez $ python main.py , il retourne:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py fait: depuis app.package_b import fun_b
  • fun_b.py fait depuis app.package_a.fun_a importer print_a

so fichier dans le dossier package_b fichier utilisé dans le dossier package_a , comme vous le souhaitez. Droit ??

Ceci est malheureusement un hack de sys.path, mais cela fonctionne assez bien.

J'ai rencontré ce problème avec une autre couche: j'avais déjà un module du nom spécifié, mais c'était un mauvais module.

Ce que je voulais faire était le suivant (le module sur lequel je travaillais était le module 3):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

Notez que j'ai déjà installé mymodule, mais que dans mon installation, je n'ai pas "mymodule1"

.

et j'obtiendrais une erreur ImportError car elle tentait d'importer à partir de mes modules installés.

J'ai essayé de faire un sys.path.append, et cela n'a pas fonctionné. Qu'est-ce qui a fonctionné était un sys.path.insert

if __name__ == '__main__':
    sys.path.insert(0, '../..')

Donc, c'est un peu comme un bidouillage, mais il faut que tout fonctionne! N'oubliez donc pas que si vous souhaitez que votre décision de remplacer les autres chemins , vous devez utiliser sys.path.insert (0, chemin d'accès) pour que cela fonctionne! Ce fut un point de blocage très frustrant pour moi, beaucoup de gens disent d'utiliser le "ajouter" fonctionne avec sys.path, mais cela ne fonctionne pas si vous avez déjà défini un module (je trouve le comportement très étrange)

Laissez-moi simplement mettre ceci ici pour ma propre référence. Je sais que ce n'est pas un bon code Python, mais j'avais besoin d'un script pour un projet sur lequel je travaillais et je voulais le placer dans un répertoire scripts .

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

Comme @EvgeniSergeev le dit dans les commentaires à l'OP, vous pouvez importer du code à partir d'un fichier .py à un emplacement quelconque avec:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Cette information provient de la réponse SO .

Jetez un coup d'œil à http: // docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . Tu pourrais faire

from .mod1 import stuff

De doc Python ,

  

Dans Python 2.5, vous pouvez basculer le comportement de l'import en absolu à l'aide d'une directive à partir de __future__ import absolute_import . Ce comportement d’importation absolue deviendra le comportement par défaut dans une version ultérieure (probablement Python 2.7). Une fois que les importations absolues sont la valeur par défaut, chaîne d'importation trouvera toujours la version de la bibliothèque standard. Il est suggéré que les utilisateurs commencent à utiliser les importations absolues autant que possible. Il est donc préférable de commencer à écrire à partir de la chaîne d'importation pkg dans votre code

.

J'ai trouvé qu'il était plus facile de définir "PYTHONPATH". variable d'environnement dans le dossier supérieur:

bash$ export PYTHONPATH=/PATH/TO/APP

alors:

import sub1.func1
#...more import

bien sûr, PYTHONPATH est "global", mais cela ne m'a pas encore posé de problèmes.

En plus de ce que John B a dit, il semble que définir la variable __ package __ devrait aider, au lieu de changer __ main __ , ce qui pourrait gâcher d'autres choses. Mais autant que j'ai pu tester, cela ne fonctionne pas complètement comme il se doit.

J'ai le même problème et ni le PEP 328 ni le 366 ne résolvent le problème complètement, car tous les deux, à la fin de la journée, il faut que la tête du paquet soit incluse dans sys.path , autant que j'ai pu comprendre.

Je dois également mentionner que je n’ai pas trouvé comment formater la chaîne qui devrait aller dans ces variables. S'agit-il de "package_head.subfolder.module_name" " ou quoi?

Supposons que vous couriez au niveau supérieur, puis dans mod1 , utilisez:

import sub2.mod2 

au lieu de

from ..sub2 import mod2
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top