Ayant déjà utilisé des paquets plats, je ne m'attendais pas au problème que j'ai rencontré avec les paquets imbriqués. Voici
Mise en page du répertoire
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Contenu de init .py
Les deux sites package/__init__.py
y package/subpackage/__init__.py
sont vides.
Contenu de module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
Contenu de test.py
(3 versions)
Version 1
# file test.py
from package.subpackage.module import *
print attribute1 # OK
C'est la manière la plus mauvaise et la moins sûre d'importer des choses (importer tout en bloc), mais cela fonctionne.
Version 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
Une façon plus sûre d'importer, élément par élément, mais cela échoue, Python ne veut pas de cela : échoue avec le message : "No module named module". Pourtant
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here
dit <module 'package.subpackage.module' from '...'>
. Donc c'est un module, mais ce n'est pas un module /-P 8-O ... uh
Version 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
Celui-ci fonctionne. Donc, soit vous êtes forcé d'utiliser le préfixe overkill tout le temps, soit vous utilisez la maniÃ?re non sà "re comme dans la version 1 et Python vous interdit d'utiliser la maniÃ?re sà "re et pratique ? La meilleure méthode, qui est sûre et évite les préfixes longs inutiles, est la seule que Python rejette ? Est-ce parce qu'il aime import *
ou parce qu'il adore les préfixes trop longs (ce qui ne contribue pas à faire respecter cette pratique) ?
Désolé pour les mots durs, mais c'est deux jours que j'essaie de contourner ce comportement stupide. À moins que je ne me sois totalement trompé quelque part, cela me laisse le sentiment que quelque chose est vraiment cassé dans le modèle de paquet et de sous-paquet de Python.
Notas
- Je ne veux pas compter sur
sys.path
pour éviter les effets secondaires globaux, ni sur*.pth
qui sont juste un autre moyen de jouer avec les fichierssys.path
avec les mêmes effets globaux. Pour que la solution soit propre, il faut qu'elle soit uniquement locale. Soit Python est capable de gérer les sous-paquets, soit il ne l'est pas, mais il ne devrait pas avoir besoin de jouer avec la configuration globale pour être capable de gérer les choses locales. - J'ai également essayé d'utiliser les importations dans
package/subpackage/__init__.py
mais cela n'a rien résolu, il fait la même chose et se plaint.subpackage
n'est pas un module connu, tandis queprint subpackage
dit que c'est un module (comportement bizarre, encore une fois).
Peut-être que je me trompe complètement (l'option que je préférerais), mais cela me déçoit beaucoup à propos de Python.
Y a-t-il un autre moyen connu en dehors des trois que j'ai essayé ? Quelque chose que je ne connais pas ?
(soupir)
----- %< ----- edit ----- >% -----
Conclusion jusqu'ici (après les commentaires des gens)
Il n'y a rien de tel qu'un vrai sous-paquetage en Python, car toutes les références de paquetage vont uniquement dans un dictionnaire global, ce qui signifie qu'il n'y a pas de dictionnaire local, ce qui implique qu'il n'y a aucun moyen de gérer les références locales de paquetage.
Vous devez utiliser soit le préfixe complet, soit le préfixe court, soit l'alias. Comme dans :
Version complète du préfixe
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
Version à préfixe court (mais préfixe répété)
from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place
Ou encore, une variation de ce qui précède.
from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context
Version factorisée
Si l'importation de plusieurs entités en une seule fois dans un lot ne vous dérange pas, vous pouvez le faire :
from package.subpackage.module import attribute1, attribute2
# and etc.
Ce n'est pas mon premier goût (je préfère avoir une déclaration d'importation par entité importée), mais c'est peut-être celui que je privilégierai personnellement.
Mise à jour (2012-09-14) :
Finalement, tout semble correct dans la pratique, à l'exception d'un commentaire sur la mise en page. Au lieu de ce qui précède, j'ai utilisé :
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.