Bien que cette question ait été posée et répondu à plusieurs reprises (par exemple, ici , ici , ici et ici ), à mon avis, aucune réponse existante ne rend compte de manière complète ou concise toutes les implications du -m
drapeau. Par conséquent, ce qui suit tentera d'améliorer ce qui a précédé.
Introduction (TLDR)
La -m
commande fait beaucoup de choses dont toutes ne seront pas nécessairement nécessaires tout le temps. En bref, il: (1) permet aux scripts python d'être exécutés via le nom de module plutôt que le nom de fichier (2) permet de choisir un répertoire à ajouter sys.path
pour la import
résolution et (3) permet aux scripts python avec des importations relatives d'être exécutés à partir de la ligne de commande .
Préliminaires
Pour expliquer le -m
drapeau, nous devons d'abord clarifier un peu la terminologie.
Premièrement, l'unité organisationnelle principale de Python est connue sous le nom de module . Les modules sont disponibles en deux versions: les modules de code et les modules de package. Un module de code est un fichier contenant du code exécutable python. Un module de package est un répertoire qui contient d'autres modules (soit des modules de code, soit des modules de package). Les types de modules de code *.py
les plus courants sont les fichiers tandis que les types les plus courants de modules de packages sont les répertoires contenant un __init__.py
fichier.
Deuxièmement, tous les modules peuvent être identifiés de manière unique de deux manières distinctes: <modulename>
et <filename>
. Les modules sont le plus souvent identifiés par nom de module dans le code Python (par exemple, import <modulename>
) et par nom de fichier sur la ligne de commande (par exemple, python <filename>
). Tous les interpréteurs Python peuvent convertir les noms de modules en noms de fichiers via un ensemble de règles bien définies. Ces règles dépendent de la sys.path
variable et par conséquent le mappage peut être modifié en changeant cette valeur (pour plus d'informations sur la façon dont cela est fait, voir PEP 302 ).
Troisièmement, tous les modules (à la fois le code et le package) peuvent être exécutés (nous entendons par là que le code associé au module sera évalué par l'interpréteur Python). En fonction de la méthode d'exécution et du type de module, le code évalué et le moment peuvent changer un peu. Par exemple, si on exécute un module de package via python <filename>
alors <filename>/__init__.py
sera évalué suivi de <filename>/__main__.py
. D'un autre côté, si l'on exécute ce même module de package via import <modulename>
alors seuls les packages __init__.py
seront exécutés.
Développement historique de -m
L'indicateur -m a été introduit pour la première fois dans Python 2.4.1 . Initialement, son seul objectif était de fournir un moyen alternatif d'identifier un module python à exécuter. Autrement dit, si nous connaissions à la fois le <filename>
et <modulename>
pour un module, les deux commandes suivantes étaient équivalentes: python <filename> <args>
et python -m <modulename> <args>
. De plus, selon PEP 338, cette itération -m
ne fonctionnait qu'avec des noms de modules de premier niveau (c'est-à-dire des modules qui pouvaient être trouvés directement sur sys.path sans aucun paquetage intermédiaire).
Avec l'achèvement du PEP 338, la -m
fonctionnalité a été étendue pour prendre en charge les <modulename>
représentations au-delà des noms de module de niveau supérieur. Cela signifiait des noms tels que http.server
désormais entièrement pris en charge. Cette amélioration signifiait également que tous les packages d'un module étaient désormais chargés (c'est-à-dire que tous les __init__.py
fichiers de packages étaient évalués), avec le module lui-même.
La dernière amélioration majeure des fonctionnalités -m
est venue avec PEP 366 . Avec cette mise -m
à jour, nous avons acquis la capacité de prendre en charge non seulement les importations absolues, mais également les importations relatives explicites. Ceci a été réalisé en modifiant la __package__
variable du module nommé dans la -m
commande.
Cas d'utilisation
Il existe deux cas d'utilisation notables pour l'indicateur -m:
Exécuter des modules à partir de la ligne de commande dont on peut ne pas connaître leur nom de fichier. Ce cas d'utilisation tire parti du fait que l'interpréteur Python sait comment convertir les noms de modules en noms de fichiers. Ceci est particulièrement avantageux lorsque l'on veut exécuter des modules stdlib ou des modules tiers à partir de la ligne de commande. Par exemple, très peu de gens connaissent le nom de fichier du http.server
module mais la plupart des gens connaissent son nom de module afin que nous puissions l'exécuter à partir de la ligne de commande en utilisant python -m http.server
.
Pour exécuter un package local contenant des importations absolues sans avoir besoin de l'installer. Ce cas d'utilisation est détaillé dans PEP 338 et tire parti du fait que le répertoire de travail actuel est ajouté sys.path
plutôt que le répertoire du module. Ce cas d'utilisation est très similaire à l'utilisation pip install -e .
pour installer un package en mode développement / édition.
Les lacunes
Avec toutes les améliorations apportées au -m
fil des ans, il présente encore un inconvénient majeur: il ne peut exécuter que des modules de code écrits en python (c'est-à-dire * .py). Par exemple, si -m
est utilisé pour exécuter un module de code compilé en C, l'erreur suivante sera produite No code object available for <modulename>
(voir ici pour plus de détails).
Comparaisons détaillées
Effets de l'exécution du module via la commande python (ie, python <filename>
):
sys.path
est modifié pour inclure le répertoire final dans <filename>
__name__
est réglé sur '__main__'
__package__
est réglé sur None
__init__.py
n'est évalué pour aucun package (y compris le sien pour les modules de package)
__main__.py
est évalué pour les modules de package; le code est évalué pour les modules de code.
Effets de l'exécution du module via une instruction d'importation (c'est-à-dire import <modulename>
):
sys.path
est pas modifié de quelque façon
__name__
prend la forme absolue de <modulename>
__package__
est défini sur le package parent immédiat dans <modulename>
__init__.py
est évalué pour tous les packages (y compris le sien pour les modules de package)
__main__.py
n'est pas évalué pour les modules de package; le code est évalué pour les modules de code
Effets de l'exécution du module via l'option -m (c'est-à-dire python -m <modulename>
):
sys.path
est modifié pour inclure le répertoire courant
__name__
est réglé sur '__main__'
__package__
est défini sur le package parent immédiat dans <modulename>
__init__.py
est évalué pour tous les packages (y compris le sien pour les modules de package)
__main__.py
est évalué pour les modules de package; le code est évalué pour les modules de code
Conclusion
L' -m
indicateur est, dans sa forme la plus simple, un moyen d'exécuter des scripts python à partir de la ligne de commande en utilisant des noms de modules plutôt que des noms de fichiers. De plus, -m
fournit des fonctionnalités supplémentaires qui combinent la puissance des import
instructions (par exemple, la prise en charge d'importations relatives explicites et l' __init__
évaluation automatique des packages ) avec la commodité de la ligne de commande python.
-m
semble recherchermymod1
dans le chemin de la bibliothèque par défaut. Exemple:python -m SimpleHTTPServer
fonctionne, maispython SimpleHTTPServer
échoue aveccan't open file 'SimpleHTTPServer': [Errno 2] No such file or directory
.