Python: l'importation d'un sous‑ensemble ou d'un sous‑module de
Avoir déjà utiliser un colis, je ne m'attendais pas à la question que j'ai rencontré avec les packages imbriqués. Ici, c'est...
La disposition des répertoires
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Contenu de init.py
Les deux package/__init__.py
et 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 le mauvais et dangereux d'importer des choses (importer le tout dans un encombrement), mais il fonctionne.
Version 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
Un moyen plus sûr d'importation, article par article, mais il échoue, Python ne veux pas de cela: échoue avec le message: "Pas de module 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 😯 ... euh
Version 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
Celui-ci fonctionne. Si vous êtes obligé d'utiliser le matraquage préfixe tout le temps ou de l'utilisation de l'insécurité façon que dans la version #1 et rejetée par Python à utiliser le coffre-fort moyen pratique? La meilleure façon de faire, qui est à l'abri et d'éviter d'inutiles long préfixe est le seul qui Python rejeter? Est-ce parce qu'il aime import *
ou parce qu'il aime trop les préfixes (ce qui n'aide pas à appliquer cette pratique)?.
Désolé pour les mots durs, mais ça fait deux jours que j'essaie de travailler autour de cette stupide comme comportement. À moins que j'ai été totalement tort, quelque part, cela me laisse avec un sentiment que quelque chose est vraiment cassé dans Python, modèle de colis et sous‑packages.
Notes
- Je ne veux pas compter sur
sys.path
, pour éviter mondiale effets secondaires, ni sur*.pth
des fichiers, qui ne sont qu'une autre façon de jouer avecsys.path
avec le même effets. Pour la solution la propreté, il doit être en local uniquement. Python est capable de gérer des sous-paquetage, soit il ne l'est pas, mais il ne devrait pas besoin de jouer avec la configuration globale pour être en mesure de traiter des matériaux locaux. - J'ai aussi essayé le recours aux importations dans
package/subpackage/__init__.py
, mais rien n'y faisait, il ne le même, et se plaintsubpackage
n'est pas un module, alors queprint subpackage
dit que c'est un module (comportement bizarre, encore une fois).
Je suis peut-être totalement faux dur (l'option que je préfère), mais cela m'a beaucoup déçu sur Python.
Tout autre moyen connu à côté des trois que j'ai essayé? Quelque chose que je ne le sais pas?
(soupir)
----- %< ----- edit ----- >% -----
Conclusion jusqu'à présent (d'après les commentaires des internautes)
Il n'y a rien comme de vrais sous‑ensemble de Python, comme toutes les références de paquet va à un mondial dictionnaire, seulement, il n'y a pas de dictionnaire, ce qui implique qu'il n'y a pas moyen de gérer le forfait local de référence.
Vous devez utiliser plein de préfixe ou de courte préfixe ou un alias. Comme dans:
Plein préfixe version
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
Court préfixe version (mais préfixe répétées)
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 d'autre, une variation de la ci-dessus.
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
Factorisée version
Si vous n'avez pas l'esprit à propos de l'importation de plusieurs entité à la fois 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 instruction d'importation par importées de l'entité), mais peut-être le seul, je vais personnellement faveur.
Mise à jour (2012-09-14):
Semble enfin s'être OK, dans la pratique, sauf avec un commentaire à propos de 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.
- Comment vont les choses lorsque vous écrivez "de . le module d'importation" en "/package/subpackage/__init__.py"?
- Votre "factorisée version" semble exactement à ce que vous voulez faire. Si vous effectuez une importation séparée de la ligne de attribut1 et attribut2 (comme vous "préférez"), vous êtes juste délibérément de vous donner plus de travail. Il n'y a pas de raison de le faire.
- Désolé mais je ne comprends pas ce que vous voulez. Pourriez-vous reformuler votre question en plus de façon claire? Qu'aimeriez-vous faire exactement? Je veux dire, qu'aimeriez-vous écrire cela ne fonctionne pas et comment vous attendez-vous à travailler? Par ce que j'ai lu, je pense que vous ce que la sémantique de l'import comme Java ou peut-être que C est de les inclure. Dernière chose: vous pouvez faire un module "star-import" sécurité de l'ajout d'un
__all__
variable qui contient une liste des noms qui doit être exportées quand un importés. edit: Bon, la lecture BrenBarn réponse que j'ai compris ce que tu voulais dire.
Vous devez vous connecter pour publier un commentaire.
Vous semblez être de l'incompréhension comment
import
recherches pour les modules. Lorsque vous utilisez une instruction import il toujours recherche le réel chemin d'accès du module (et/ousys.modules
); il n'est pas utiliser le module objets dans l'espace de noms local qui existent en raison des importations antérieures. Lorsque vous faites:La deuxième ligne est un paquet
package.subpackage
et les importationsmodule
de ce package. Cette ligne n'a pas d'effet sur la troisième ligne. La troisième ligne semble juste pour un module appelémodule
et de ne pas en trouver un. Il n'a pas de "réutiliser" l'objet appelémodule
que vous avez obtenu à partir de la ligne au-dessus.En d'autres termes
from someModule import ...
ne veut pas dire "à partir du module appelé someModule que j'ai importé tout à l'heure...", cela signifie "à partir du module nommé someModule que vous trouverez sur sys.chemin d'accès...". Il n'y a aucun moyen de "progressivement" construire un module de chemin d'accès par l'importation de paquets qui y conduisent. Vous devez toujours vous référer à l'ensemble du nom du module lors de l'importation.Il n'est pas clair ce que vous essayez d'atteindre. Si vous ne souhaitez importer l'objet particulier attribut1, il suffit de faire
from package.subpackage.module import attribute1
et être fait avec elle. Vous ne devez pas vous inquiéter au sujet de la longuepackage.subpackage.module
une fois que vous avez importé le nom que vous voulez à partir d'elle.Si vous ne voulez avoir accès au module pour accéder à d'autres noms plus tard, alors vous pouvez faire
from package.subpackage import module
et, comme vous l'avez vu, vous pouvez alors fairemodule.attribute1
et ainsi de suite autant que vous le souhaitez.Si vous voulez les deux --- qui est, si vous voulez
attribute1
directement accessible et vous voulezmodule
accessible, il suffit de faire les deux:Si vous n'aimez pas taper
package.subpackage
même deux fois, vous pouvez simplement créer manuellement une référence locale à attribut1:module.attribute1
est quelque chose que j'ai bien sur, mais je pensais qu'il y aurait un moyen d'éviter la nécessité d'un préfixe de partout. Donc, je dois utiliser un préfixe à chaque où la, ou la création d'un alias local, de répéter le nom. Pas le style que je m'attendais, mais si il n'y a pas moyen (après tout, je suis habitué à Ada, qui exige quelque chose de similaire avec son changement de nom des déclarations).La raison #2 échoue est parce que
sys.modules['module']
n'existe pas (la routine d'importation a son propre champ, et ne peut pas voir lamodule
nom local), et il n'y a pasmodule
module ou le paquet sur le disque. Notez que vous pouvez séparer plusieurs importés noms par des virgules.Aussi:
sys.modules['name']
que je ne connaissais pas jusqu'à maintenant, m'a fait penser que c'est ce que j'ai eu peur (et BrenBarn confirme: il n'y a rien comme de vrais sous‑packages Python.sys.modules
, comme son nom l'indique, est global, et si toute référence à des modules de compter sur cela, alors il n'y a rien comme une référence locale à un module (peut être à venir avec Python 3.x?).import
#2 génère une référence locale àpackage.subpackage.module
lié àmodule
.Si tout ce que vous essayez de faire est d'obtenir attribut1 dans votre espace de noms global, version 3 est semble bien. Pourquoi est-il exagéré préfixe ?
Dans la version 2, au lieu de
vous pouvez faire
attribute1 = module.attribute1
est juste de répéter le nom à non-valeur ajoutée. Je sais que ça fonctionne, mais je n'aime pas ce style (qui n'implique que je n'aime pas votre réponse).