Voici une explication. La version courte est qu'il y a une grande différence entre directement l'exécution d'un fichier Python, et l'importation de ce fichier à partir de quelque part d'autre. De savoir que ce répertoire un fichier ne permet pas de déterminer quel paquet Python pense qu'il est dans. Cela dépend, en outre, sur la façon dont vous chargez le fichier en Python (en cours d'exécution ou par l'importation).
Il y a deux façons de charger un fichier Python: le script de niveau supérieur, ou comme un
le module. Un fichier est chargé dans le script de niveau supérieur si vous l'exécuter directement, par exemple en tapant python myfile.py
sur la ligne de commande. Il est chargé en tant que module si vous n' python -m myfile
, ou s'il est chargé lorsque l' import
déclaration est encounted à l'intérieur d'un autre fichier. Il peut seulement être un script de niveau supérieur à un temps; le script de niveau supérieur est le fichier Python vous avez exécuté, pour commencer.
Lorsqu'un fichier est chargé, il est donné un nom (qui est stocké dans ses __name__
d'attribut). Si il a été chargé comme le script de niveau supérieur, son nom est __main__
. Si il a été chargé en tant que module, son nom est le nom de fichier, précédé par le nom de tous les ensembles/sous-paquets dont il fait partie, séparés par des points.
Ainsi, par exemple, dans votre exemple, si vous avez importé moduleX
(note: importés, ne sont pas directement exécuté), son nom serait package.subpackage1.moduleX
. Si vous avez importé moduleA
, son nom serait package.moduleA
. Toutefois, si vous exécutez directement moduleX
à partir de la ligne de commande, son nom sera à la place __main__
, et si vous exécutez directement moduleA
à partir de la ligne de commande, son nom sera __main__
. Lorsqu'un module est exécuté le script de niveau supérieur, il perd son nom normal et son nom est plutôt __main__
.
Il existe une ride: le module du nom dépend de si elle a été importée "directement" à partir du répertoire il est ou importés par l'intermédiaire d'un package. Cela ne fait qu'une différence si vous exécutez Python dans un répertoire, et essayez d'importer un fichier dans le même répertoire (ou un sous-répertoire de celui-ci). Par exemple, si vous lancez l'interpréteur Python dans le répertoire package/subpackage1
puis effectuez l' import moduleX
, le nom de l' moduleX
sera moduleX
, et pas package.subpackage1.moduleX
. C'est parce que Python ajoute le répertoire courant de son chemin de recherche sur le démarrage; si elle trouve le pour-être-module importé dans le répertoire courant, il ne saura pas que ce répertoire est partie d'un paquet et le paquet de l'information ne font pas partie intégrante du module du même nom.
Un cas spécial est de savoir si vous exécutez l'interprète de manière interactive (par exemple, il suffit de taper python
et de commencer la saisie du code Python à la volée). Dans ce cas, le nom de cette session interactive est - __main__
.
Maintenant, voici la chose cruciale pour votre message d'erreur: si le nom d'un module n'a pas de points, il n'est pas considéré comme faisant partie d'un package. Il n'a pas d'importance où le fichier est en fait sur le disque. Tout ce qui compte c'est ce que son nom, et son nom dépend de la façon dont vous l'a chargé.
Regardez maintenant le devis que vous avez inclus dans votre question:
Relative des importations de l'utilisation d'un module du nom de l'attribut pour déterminer le module de la position dans la hiérarchie des paquets. Si le module est le nom ne contient pas toute l'information de l'emballage (par exemple, il est à 'principal') puis par rapport importations sont résolus que si le module ont été d'un haut niveau module, indépendamment de l'endroit où le module est en fait situé sur le système de fichiers.
Relative des importations de l'utilisation du module de nom afin de déterminer où il se trouve dans un paquet. Lorsque vous utilisez l'un par rapport à l'importation comme from .. import foo
, les points de suspension indiquent à l'étape jusqu'certain nombre de niveaux dans la hiérarchie des paquets. Par exemple, si votre module en cours nom de l' package.subpackage1.moduleX
, alors ..moduleA
signifierait package.moduleA
. Pour un from .. import
de travail, le module du nom doit avoir au moins autant de points qu'il y a dans la import
déclaration.
Toutefois, si votre module est le nom est __main__
, il n'est pas considéré comme un paquet. Son nom n'a pas de points, et, par conséquent, vous ne pouvez pas utiliser from .. import
états à l'intérieur. Si vous essayez de le faire, vous obtiendrez le "relatif à l'importation dans la non-package" erreur.
Ce que vous avez probablement fait, c'est que vous avez essayé d'exécuter moduleX
ou à partir de la ligne de commande. Lorsque vous avez fait cela, son nom a été mis à l' __main__
, ce qui signifie que, par rapport des importations à l'intérieur, il sera un échec, car son nom ne révèle pas qu'il est dans un package. Notez qu'il sera également se produire si vous exécutez Python dans le même répertoire où se trouve un module, puis essayez d'importer ce module, parce que, comme décrit ci-dessus, Python trouverez le module dans le répertoire courant "trop tôt" sans se rendre compte qu'il fait partie d'un package.
Rappelez-vous aussi que lorsque vous exécutez l'interactive interprète, le "nom" de cette session interactive est toujours __main__
. Donc vous ne pouvez pas le faire par rapport importations directement à partir d'une session interactive. Relative des importations sont uniquement pour l'utilisation dans le module de fichiers.
Il y a deux solutions à cela. Si vraiment vous ne voulez pas exécuter moduleX
directement, mais vous voulez toujours être considéré comme faisant partie d'un package, vous pouvez le faire python -m package.subpackage.moduleX
. L' -m
indique à Python pour charger un module, non pas comme le script de niveau supérieur.
Ou peut-être vous n'avez pas vraiment envie de courir moduleX
, vous voulez juste pour exécuter un script, dire myfile.py
, qui utilise des fonctions à l'intérieur d' moduleX
. Si c'est le cas, placez myfile.py
ailleurs --- pas à l'intérieur de l' package
annuaire, et l'exécuter. Si à l'intérieur d' myfile.py
vous faire des choses comme from package.moduleA import spam
, cela fonctionnera très bien.
À noter que pour l'une de ces solutions, le répertoire du package (package
dans l'exemple) doit être accessible à partir du module Python chemin de recherche (sys.path
). Si elle n'est pas, vous ne serez pas en mesure d'utiliser quoi que ce soit dans le package de façon fiable à tous.
(Une technique remarque: depuis la version 2.6 de Python, le module de "nom" pour le paquet de résolution est déterminée non seulement par ses __name__
attributs, mais aussi par l' __package__
d'attribut. C'est pourquoi j'évite d'utiliser le symbole explicite __name__
de vous référer au module "nom". Depuis la version 2.6 de Python d'un module "nom" est efficacement __package__ + '.' + __name__
, ou juste __name__
si __package__
est None
.)