265 votes

À quoi sert le commutateur -m ?

Pourriez-vous m'expliquer quelle est la différence entre le fait d'appeler

python -m mymod1 mymod2.py args

y

python mymod1.py mymod2.py args

Il semble que dans les deux cas mymod1.py est appelé et sys.argv es

['mymod1.py', 'mymod2.py', 'args']

Qu'est-ce que la -m pour quoi faire ?

0 votes

Veuillez me corriger si je me trompe, mais -m semble rechercher mymod1 dans le chemin de la bibliothèque par défaut. Exemple : python -m SimpleHTTPServer fonctionne, alors que python SimpleHTTPServer échoue avec can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory .

15 votes

En fait, j'ai trouvé la réponse ici plus claire : stackoverflow.com/questions/46319694/

180voto

agf Points 45052

La première ligne du Rationale section de PEP 338 dit :

Python 2.4 ajoute le commutateur de ligne de commande -m pour permettre aux modules d'être localisés en utilisant l'espace de noms des modules Python pour l'exécution en tant que scripts. Les exemples motivants étaient des modules de la bibliothèque standard tels que pdb et profile, et l'implémentation de Python 2.4 convient parfaitement à cet objectif limité.

Vous pouvez donc spécifier n'importe quel module dans le chemin de recherche de Python de cette manière, et pas seulement les fichiers du répertoire courant. Vous avez raison de dire que python mymod1.py mymod2.py args a exactement le même effet. La première ligne du Scope of this proposal La section de l'article 2 de la loi sur l'immigration et la protection des réfugiés stipule que

Dans Python 2.4, un module localisé à l'aide de -m est exécuté comme si son nom de fichier avait été fourni sur la ligne de commande.

Avec -m Il est possible d'aller plus loin, par exemple en travaillant avec des modules qui font partie d'un paquet, etc. C'est l'objet du reste du PEP 338. Lisez-le pour plus d'informations.

118voto

Mark Rucker Points 2198

Bien que cette question ait été posée et résolue à plusieurs reprises (ex, aquí , aquí , aquí y aquí ), je pense qu'aucune réponse existante ne permet d'appréhender de manière complète ou concise toutes les implications de l'initiative de l -m drapeau. C'est pourquoi ce qui suit tentera d'améliorer ce qui a été fait jusqu'à présent.

Introduction (TLDR)

Le -m Le drapeau fait beaucoup de choses, qui ne sont pas toutes nécessaires en permanence. En bref, il peut être utilisé pour (1) exécuter du code python depuis la ligne de commande via modulename plutôt que filename (2) ajouter un répertoire à sys.path à utiliser dans import et (3) exécuter du code python contenant des importations relatives à partir de la ligne de commande.

Préliminaires

Pour expliquer la -m Il faut d'abord expliquer un peu la terminologie.

L'unité organisationnelle principale de Python est connue sous le nom de module . Les modules se présentent sous deux formes : les modules de code et les modules de paquetage. Un module de code est un fichier qui contient du code exécutable en Python. Un module de paquetage est un répertoire qui contient d'autres modules (soit des modules de code, soit des modules de paquetage). Les modules de code les plus courants sont les suivants *.py tandis que le type le plus courant de modules de paquetage est constitué de répertoires contenant un fichier __init__.py fichier.

Python permet d'identifier les modules de deux manières distinctes : le nom du module et le nom du fichier. En général, les modules sont identifiés par leur 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ètes python sont capables de convertir des noms de modules en noms de fichiers en suivant les mêmes quelques règles bien définies. Ces règles s'articulent autour de la fonction sys.path variable. En modifiant cette variable, on peut changer la façon dont Python résout les noms de modules en noms de fichiers (pour plus d'informations sur la façon de procéder, voir PEP 302 ).

Tous les modules (code et paquetage) peuvent être exécutés (c'est-à-dire 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 où il l'est peuvent changer considérablement. Par exemple, si l'on exécute un module de paquetage via python <filename> puis <filename>/__main__.py sera exécutée. D'autre part, si l'on exécute ce même module de paquetage via import <modulename> alors seulement le __init__.py sera exécutée.

Développement historique de la -m

Le -m Le drapeau a été introduit pour la première fois en Python 2.4.1 . Au départ, son seul objectif était de fournir un moyen alternatif d'identifier le module python à exécuter à partir de la ligne de commande. En d'autres termes, si nous connaissions à la fois le <filename> y <modulename> pour un module, les deux commandes suivantes sont équivalentes : python <filename> <args> y python -m <modulename> <args> . Une contrainte avec cette itération, selon PEP 338 était que -m ne fonctionne qu'avec les noms de modules de premier niveau (c'est-à-dire les modules qui peuvent être trouvés directement sur sys.path sans aucun module de paquetage intermédiaire).

Avec l'achèvement de la PEP 338 les -m a été étendue à la prise en charge des <modulename> des représentations au-delà du niveau le plus élevé. Cela signifiait des noms tels que http.server sont désormais pleinement pris en charge. Cette extension signifie également que chaque paquet parent dans le nom du module est désormais évalué (c'est-à-dire que tous les paquets parents __init__.py ont été évalués) en plus du module référencé par le nom de module lui-même.

La dernière amélioration majeure de la fonctionnalité de -m est venu avec PEP 366 . Avec cette mise à niveau -m a acquis la capacité de prendre en charge non seulement les importations absolues, mais aussi les importations relatives explicites lors de l'exécution des modules. Ceci a été réalisé en changeant -m de manière à ce qu'il fixe le __package__ au module parent du nom de module donné (en plus de tout ce qu'il a déjà fait).

Cas d'utilisation

Il existe deux cas d'utilisation notables pour le -m drapeau :

  1. Pour exécuter des modules à partir de la ligne de commande dont on ne connaît pas le 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 module http.server mais la plupart des gens connaissent son nom de module, de sorte que nous pouvons l'exécuter à partir de la ligne de commande à l'aide de la commande python -m http.server .

  2. Exécuter un paquet local contenant des importations absolues ou relatives sans avoir à 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 de pip install -e . pour installer un paquet en mode développement/édition.

Lacunes

Avec toutes les améliorations apportées à -m au fil des ans, il présente toujours une lacune majeure : il ne peut exécuter que des modules é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 aquí pour plus de détails).

Comparaisons détaillées

Exécution d'un module via une déclaration d'importation (c'est-à-dire, import <modulename> ):

  • sys.path es no modifié de quelque manière que ce soit
  • __name__ est fixé à la forme absolue de <modulename>
  • __package__ est fixé au paquet parent immédiat dans <modulename>
  • __init__.py est évalué pour tous les paquets (y compris le sien pour les modules du paquet)
  • __main__.py es no évalué pour les modules de paquetage ; le code est évalué pour les modules de code

Exécution du module via la ligne de commande avec le nom du fichier (c'est-à-dire, python <filename> ):

  • sys.path est modifié pour inclure le répertoire final dans <filename>
  • __name__ est fixé à '__main__'
  • __package__ est fixé à None
  • __init__.py n'est évalué pour aucun paquet (y compris le sien pour les modules du paquet)
  • __main__.py est évalué pour les modules de paquetage ; le code est évalué pour les modules de code.

Exécution du module via la ligne de commande avec le nom du module (c'est-à-dire, python -m <modulename> ):

  • sys.path est modifié pour inclure le répertoire actuel
  • __name__ est fixé à '__main__'
  • __package__ est fixé au paquet parent immédiat dans <modulename>
  • __init__.py est évalué pour tous les paquets (y compris le sien pour les modules du paquet)
  • __main__.py est évalué pour les modules de paquetage ; le code est évalué pour les modules de code

Conclusion

Le -m 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. La véritable puissance de l'option -m Cependant, le succès de l'initiative réside dans sa capacité à combiner la puissance de la technologie de l'information et de la communication (TIC). import (par exemple, prise en charge des importations relatives explicites et des paquets automatiques). __init__ ) avec la commodité de la ligne de commande.

32voto

Marquez.Z Points 131

Il convient de mentionner cela ne fonctionne que si le paquet a un fichier __main__.py Dans le cas contraire, ce paquet ne peut pas être exécuté directement.

python -m some_package some_arguments

L'interpréteur python recherchera un fichier __main__.py dans le chemin du paquet pour l'exécuter. C'est l'équivalent de :

python path_to_package/__main__.py somearguments

Il exécutera le contenu après :

if __name__ == "__main__":

2 votes

Qu'en est-il du fichier init du paquet ? En présence du fichier principal, le fichier init sera-t-il également invoqué ?

0 votes

@variable Oui init .py sera invoqué avant principal .py est invoqué

0 votes

Ceci n'est pas exact. si vous essayez d'exécuter directement le principal .py d'un paquet, cela ne fonctionnerait pas car vous devriez exécuter le paquet avec l'option python -m.

5voto

yyFred Points 192

Je voudrais juste mentionner un cas qui pourrait prêter à confusion.

Supposons que vous utilisiez pip3 pour installer un paquet foo qui contient un bar module. Cela signifie que vous pouvez exécuter python3 -m foo.bar à partir de n'importe quel répertoire. D'autre part, vous avez une structure de répertoire comme celle-ci :

src
|
+-- foo
    |
    +-- __init__.py
    |
    +-- bar.py

Vous êtes à src/ . Lorsque vous exécutez python -m foo.bar vous exécutez le programme bar.py au lieu du module installé. Cependant, si vous appelez python -m foo.bar à partir d'un autre répertoire, vous utilisez le module installé.

Ce comportement ne se produit certainement pas si vous utilisez la fonction python au lieu de python -m et peut être déroutant pour les débutants. La raison en est l'ordre dans lequel Python recherche les modules.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X