Ayant déjà utilisé des packages plats, je n'attendais pas le problème rencontré avec les packages imbriqués. Voici…
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Tous les deux package/__init__.py
et package/subpackage/__init__.py
sont vides.
module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
test.py
(3 versions)# file test.py
from package.subpackage.module import *
print attribute1 # OK
C'est la façon mauvaise et peu sûre d'importer des choses (tout importer en vrac), mais cela fonctionne.
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
Un moyen plus sûr d’importer, élément par élément, mais il échoue, Python ne veut pas ceci: échoue avec le message: "Aucun module nommé module". Cependant…
# 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 ... euh
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
Celui-ci fonctionne. Donc, vous êtes obligé d'utiliser le préfixe overkill tout le temps ou d'utiliser la méthode non sécurisée comme dans la version 1 et interdite par Python pour utiliser la méthode sécurisée et pratique? La meilleure façon, qui est sécurisée et éviter les préfixes longs non nécessaires est le seul qui Python rejette? Est-ce parce qu'il aime import *
ou parce qu’il aime les préfixes trop longs (ce qui n’aide pas à appliquer cette pratique) ?.
Désolé pour les mots durs, mais cela fait deux jours que j'essaie de contourner ce comportement stupide. À moins que je ne sois totalement trompé quelque part, cela me laissera le sentiment que quelque chose est vraiment cassé dans le modèle de paquet et de sous-paquet de Python.
Remarques
sys.path
, pour éviter les effets secondaires globaux, ni sur *.pth
fichiers, qui ne sont qu’un autre moyen de jouer avec sys.path
avec les mêmes effets globaux. Pour que la solution soit propre, elle doit être locale uniquement. Soit Python est capable de gérer les sous-packages, mais ce n’est pas nécessaire, mais cela ne devrait pas nécessiter de jouer avec la configuration globale pour pouvoir gérer les éléments locaux.package/subpackage/__init__.py
, mais il n’a rien résolu, il fait de même et se plaint subpackage
n’est pas un module connu, alors que print subpackage
dit que c'est un module (comportement étrange, encore).Peut-être que je me trompe complètement (l'option que je préférerais), mais cela me déçoit beaucoup à propos de Python.
Un autre moyen connu à côté des trois j'ai essayé? Quelque chose que je ne connais pas?
(soupir)
-----% <----- edit ----->% -----
Il n'y a rien de tel qu'un vrai sous-paquet dans Python, car toutes les références de paquet vont à 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 la référence de paquet local.
Vous devez utiliser un préfixe complet ou un préfixe court ou un alias. Un péché:
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
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 bien, une variante 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
Si vous ne voulez pas importer plusieurs entités en même temps dans un lot, vous pouvez:
from package.subpackage.module import attribute1, attribute2
# and etc.
Pas dans mon premier goût préféré (je préfère avoir une déclaration d'importation par entité importée), mais c'est peut-être celle que je privilégierai personnellement.
Mise à jour (2012-09-14):
Finalement, ça semble être OK dans la pratique, sauf avec 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.
Vous semblez avoir mal compris comment import
cherche des modules. Lorsque vous utilisez une instruction import, elle toujours recherche le chemin du module actuel (et/ou sys.modules
); il n'utilise pas le module objets dans l'espace de noms local qui existe en raison d'importations précédentes. Quand tu fais:
import package.subpackage.module
from package.subpackage import module
from module import attribute1
La deuxième ligne cherche un paquet nommé package.subpackage
et importe module
de ce paquet. Cette ligne n'a aucun effet sur la troisième ligne. La troisième ligne recherche simplement un module appelé module
et n'en trouve pas. Il ne "réutilise" pas l'objet appelé module
que vous avez obtenu à partir de la ligne ci-dessus.
En d'autres termes from someModule import ...
ne signifie pas "du module appelé someModule que j’avais importé auparavant ...", cela signifie "du module nommé someModule que vous trouvez sur sys.path ...". Il n'y a aucun moyen de "incrémenter" le chemin d'un module en important les packages qui y mènent. Vous devez toujours faire référence au nom complet du module lors de l'importation.
Ce que vous essayez d'accomplir n'est pas clair. Si vous voulez seulement importer l'objet attribut1 particulier, faites juste from package.subpackage.module import attribute1
et en finir avec ça. Vous ne devez jamais vous soucier de la longue package.subpackage.module
une fois que vous avez importé le nom de votre choix.
Si vous faites voulez avoir accès au module pour accéder ultérieurement à d'autres noms, vous pouvez alors faire from package.subpackage import module
et, comme vous l'avez vu, vous pouvez alors faire module.attribute1
et ainsi de suite autant que vous le souhaitez.
Si vous voulez les deux --- c'est-à-dire, si vous voulez attribute1
directement accessible et vous voulez module
accessible, faites simplement les deux choses ci-dessus:
from package.subpackage import module
from package.subpackage.module import attribute1
attribute1 # works
module.someOtherAttribute # also works
Si vous n'aimez pas taper package.subpackage
même deux fois, vous pouvez simplement créer manuellement une référence locale à attribut1:
from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works
La raison n ° 2 échoue parce que sys.modules['module']
_ n'existe pas (la routine d'importation a sa propre portée et ne peut pas voir le nom local module
.) et il n'y a pas de module ni de package module
sur disque. Notez que vous pouvez séparer plusieurs noms importés par des virgules.
from package.subpackage.module import attribute1, attribute2, attribute3
Également:
from package.subpackage import module
print module.attribute1
Si tout ce que vous essayez de faire est d’obtenir attribut1 dans votre espace de noms global, la version 3 semble très bien. Pourquoi est-ce préfixe overkill?
Dans la version 2, au lieu de
from module import attribute1
tu peux faire
attribute1 = module.attribute1