Lorsque vous utilisez l' -m
indicateur de ligne de commande , Python importera un module ou un package pour vous, puis l'exécutera en tant que script. Lorsque vous n'utilisez pas l' -m
indicateur, le fichier que vous avez nommé est exécuté comme un simple script .
La distinction est importante lorsque vous essayez d'exécuter un package. Il y a une grande différence entre:
python foo/bar/baz.py
et
python -m foo.bar.baz
comme dans ce dernier cas, foo.bar
est importé et les importations relatives fonctionneront correctement avec foo.bar
comme point de départ.
Démo:
$ mkdir -p test/foo/bar
$ touch test/foo/__init__.py
$ touch test/foo/bar/__init__.py
$ cat << EOF > test/foo/bar/baz.py
> if __name__ == "__main__":
> print __package__
> print __name__
>
> EOF
$ PYTHONPATH=test python test/foo/bar/baz.py
None
__main__
$ PYTHONPATH=test python -m foo.bar.baz
foo.bar
__main__
En conséquence, Python doit réellement se soucier des packages lors de l'utilisation du -m
commutateur. Un script normal ne peut jamais être un package, il __package__
est donc défini sur None
.
Mais exécutez un package ou un module à l' intérieur d' un package avec -m
et maintenant il y a au moins la possibilité d'un package, donc la __package__
variable est définie sur une valeur de chaîne; dans la démonstration ci-dessus, il est défini sur foo.bar
, pour les modules simples ne figurant pas dans un package, il est défini sur une chaîne vide.
Quant au __main__
module ; Python importe les scripts en cours d'exécution comme un module normal. Un nouvel objet module est créé pour contenir l'espace de noms global, stocké dans sys.modules['__main__']
. C'est à cela que se __name__
réfère la variable, c'est une clé dans cette structure.
Pour les packages, vous pouvez créer un __main__.py
module et l'exécuter lors de l'exécution python -m package_name
; en fait , qui est la seule façon que vous pouvez exécuter un package en tant que script:
$ PYTHONPATH=test python -m foo.bar
python: No module named foo.bar.__main__; 'foo.bar' is a package and cannot be directly executed
$ cp test/foo/bar/baz.py test/foo/bar/__main__.py
$ PYTHONPATH=test python -m foo.bar
foo.bar
__main__
Ainsi, lors de la désignation d'un package à exécuter avec -m
, Python recherche un __main__
module contenu dans ce package et l'exécute en tant que script. Son nom est alors toujours défini sur __main__
, et l'objet module est toujours stocké dans sys.modules['__main__']
.
PYTHONPATH=test python -m foo.bar
signifie réellement la commande ? Pourriez-vous l'expliquer en détail, s'il vous plaît?PYTHONPATH
définit une variable d'environnement; il étend la série de répertoires où Python recherchera les modules lors de l'importation; ici, il ajoute letest
répertoire à cette série. En le plaçant sur la même ligne de commande, il ne s'applique qu'à cette seulepython
commande.-m
dit à Python d'importer un module spécifique, comme si vous exécutiezimport foo.bar
. Cependant, Python exécutera automatiquement un__main__
module dans un package en tant que script lorsque vous utilisez ce commutateur.having to use -m always is not that user-.friendly.
Je pense que le fait d'utiliser et de ne pas utiliser-m
est moins convivial.-m
ne fonctionne que pour le répertoire courant ou les répertoires déjà enregistrés sur le chemin de recherche. C'était mon point.-m
n'est pas quelque chose que vous donnez aux utilisateurs finaux pour ce problème de convivialité.from Photos import ...
va se plaindre. Il en serait de mêmeimport Photos.<something>
.import Photos
ne fonctionne que parce que Python prend en charge les packages d'espacement de noms (où deux distributions distinctes fournissentPhotos.foo
etPhotos.bar
séparément et peuvent être gérées indépendamment).Exécution de code Python avec l'option -m ou non
Utilisez le
-m
drapeau.Les résultats sont à peu près les mêmes lorsque vous avez un script, mais lorsque vous développez un package, sans l'
-m
indicateur, il n'y a aucun moyen de faire fonctionner correctement les importations si vous souhaitez exécuter un sous-package ou un module dans le package en tant qu'entrée principale montrez votre programme (et croyez-moi, j'ai essayé.)Les docs
Comme les documents sur l'indicateur -m disent:
et
alors
équivaut à peu près à
(en supposant que vous n'avez pas de package ou de script dans votre répertoire actuel appelé pdb.py)
Explication:
Le comportement est rendu «délibérément similaire aux» scripts.
Un certain code python est destiné à être exécuté en tant que module: (Je pense que cet exemple est meilleur que l'exemple de doc d'option de ligne de commande)
Et d'après les faits saillants de la note de publication pour Python 2.4 :
Question de suivi
Cela signifie que tout module que vous pouvez rechercher avec une instruction d'importation peut être exécuté comme point d'entrée du programme - s'il a un bloc de code, généralement vers la fin, avec
if __name__ == '__main__':
.-m
sans ajouter le répertoire courant au chemin:Un commentaire ici ailleurs dit:
Eh bien, cela démontre le problème possible - (dans Windows, supprimez les guillemets):
Utilisez l'
-I
indicateur pour verrouiller cela pour les environnements de production (nouveau dans la version 3.4):à partir de la documentation :
Que fait
__package__
-on?Cela permet des importations relatives explicites, pas particulièrement pertinentes pour cette question, cependant - voir cette réponse ici: Quel est le but de l'attribut «__package__» en Python?
la source
La principale raison d'exécuter un module (ou package) en tant que script avec -m est de simplifier le déploiement, en particulier sous Windows. Vous pouvez installer des scripts au même endroit dans la bibliothèque Python où les modules vont normalement - au lieu de polluer PATH ou des répertoires exécutables globaux tels que ~ / .local (le répertoire de scripts par utilisateur est ridiculement difficile à trouver dans Windows).
Ensuite, vous tapez simplement -m et Python trouve le script automatiquement. Par exemple,
python -m pip
trouvera le bon pip pour la même instance de l'interpréteur Python qui l'exécute. Sans -m, si l'utilisateur a plusieurs versions de Python installées, laquelle serait le pip "global"?Si l'utilisateur préfère les points d'entrée "classiques" pour les scripts de ligne de commande, ceux-ci peuvent être facilement ajoutés sous forme de petits scripts quelque part dans PATH, ou pip peut les créer au moment de l'installation avec le paramètre entry_points dans setup.py.
Il suffit donc de vérifier
__name__ == '__main__'
et d'ignorer les autres détails d'implémentation non fiables.la source