¿Cuál es el propósito del modificador -m?

Resuelto Charles Brunet asked hace 13 años • 6 respuestas

¿Podrías explicarme cuál es la diferencia entre llamar?

python -m mymod1 mymod2.py args

y

python mymod1.py mymod2.py args

Parece que en ambos casos mymod1.pyse llama y sys.argves

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

Entonces, ¿para qué sirve el -minterruptor?

Charles Brunet avatar Sep 30 '11 18:09 Charles Brunet
Aceptado

A pesar de que esta pregunta ha sido formulada y respondida varias veces (por ejemplo, aquí , aquí , aquí y aquí ), en mi opinión, ninguna respuesta existente captura completa o concisamente todas las implicaciones de la -mbandera. Por lo tanto, lo siguiente intentará mejorar lo anterior.

Introducción (TLDR)

La -mbandera hace muchas cosas, pero no todas serán necesarias todo el tiempo. En resumen, se puede usar para: (1) ejecutar código Python desde la línea de comando a través del nombre del módulo en lugar del nombre del archivo (2) agregar un directorio para sys.pathusarlo en importla resolución y (3) ejecutar código Python que contiene importaciones relativas desde la línea de comando .

Preliminares

Para explicar la -mbandera primero necesitamos explicar un poco de terminología.

La unidad organizativa principal de Python se conoce como módulo . Los módulos vienen en uno de dos tipos: módulos de código y módulos de paquete. Un módulo de código es cualquier archivo que contiene código ejecutable de Python. Un módulo de paquete es cualquier directorio que contiene otros módulos (ya sean módulos de código o módulos de paquete). El tipo más común de módulo de código es un *.pyarchivo, mientras que el tipo más común de módulo de paquete es un directorio que contiene un __init__.pyarchivo.

Python permite que los módulos se identifiquen de forma única de dos maneras: nombre de módulo y nombre de archivo. En general, los módulos se identifican por el nombre del módulo en el código Python (por ejemplo, import <modulename>) y por el nombre del archivo en la línea de comando (por ejemplo, python <filename>). Todos los intérpretes de Python pueden convertir nombres de módulos en nombres de archivos siguiendo las mismas reglas bien definidas. Estas reglas dependen de la sys.pathvariable. Al alterar esta variable se puede cambiar la forma en que Python resuelve los nombres de los módulos en nombres de archivos (para obtener más información sobre cómo se hace esto, consulte PEP 302 ).

Todos los módulos (tanto el código como el paquete) se pueden ejecutar (es decir, el intérprete de Python evaluará el código asociado con el módulo). Dependiendo del método de ejecución (y del tipo de módulo), qué código se evalúa y cuándo puede cambiar bastante. Por ejemplo, si uno ejecuta un módulo de paquete a través de, python <filename>se <filename>/__main__.pyejecutará. Por otro lado, si uno ejecuta ese mismo módulo de paquete , solo se ejecutará import <modulename>el paquete .__init__.py

Desarrollo histórico de-m

La -mbandera se introdujo por primera vez en Python 2.4.1 . Inicialmente, su único propósito era proporcionar un medio alternativo para identificar el módulo de Python para ejecutar desde la línea de comando. Es decir, si conociéramos tanto el <filename>como <modulename>para un módulo, entonces los dos comandos siguientes serían equivalentes: python <filename> <args>y python -m <modulename> <args>. Una limitación de esta iteración, según PEP 338 , era que -msolo funcionaba con nombres de módulos de nivel superior (es decir, módulos que se podían encontrar directamente sys.pathsin ningún módulo de paquete intermedio).

Con la finalización de PEP 338, la -mfunción se amplió para admitir <modulename>representaciones más allá del nivel superior. Esto significó que nombres como este http.serverahora fueran totalmente compatibles. Esta extensión también significó que cada paquete principal en nombre del módulo ahora se evaluó (es decir, se evaluaron todos los archivos del paquete principal __init__.py) además del módulo al que hace referencia el propio nombre del módulo.

La última mejora importante de funciones -mllegó con PEP 366 . Con esta actualización -mse obtuvo la capacidad de admitir no solo importaciones absolutas sino también importaciones relativas explícitas al ejecutar módulos. Esto se logró cambiando -mpara que estableciera la __package__variable en el módulo principal del nombre del módulo dado (además de todo lo demás que ya hizo).

Casos de uso

Hay dos casos de uso notables para la -mbandera:

  1. Para ejecutar módulos desde la línea de comando de los cuales es posible que no se conozca su nombre de archivo. Este caso de uso aprovecha el hecho de que el intérprete de Python sabe cómo convertir nombres de módulos en nombres de archivos. Esto es particularmente ventajoso cuando se desea ejecutar módulos stdlib o módulos de terceros desde la línea de comandos. Por ejemplo, muy pocas personas conocen el nombre del archivo del http.servermódulo, pero la mayoría sí conoce el nombre del módulo, por lo que podemos ejecutarlo desde la línea de comando usando python -m http.server.

  2. Para ejecutar un paquete local que contiene importaciones absolutas o relativas sin necesidad de instalarlo. Este caso de uso se detalla en PEP 338 y aprovecha el hecho de que se agrega el directorio de trabajo actual sys.pathen lugar del directorio del módulo. Este caso de uso es muy similar al uso pip install -e .para instalar un paquete en modo desarrollo/edición.

Deficiencias

Con todas las mejoras realizadas a -mlo largo de los años, todavía tiene una deficiencia importante: sólo puede ejecutar módulos escritos en Python (es decir, *.py). Por ejemplo, si -mse utiliza para ejecutar un módulo de código compilado en C, se producirá el siguiente error No code object available for <modulename>(consulte aquí para obtener más detalles).

Comparaciones detalladas

Ejecución del módulo mediante declaración de importación (es decir, import <modulename>):

  • sys.pathno se modifica de ninguna manera
  • __name__se establece en la forma absoluta de<modulename>
  • __package__está configurado en el paquete principal inmediato en<modulename>
  • __init__.pyse evalúa para todos los paquetes (incluido el suyo propio para los módulos del paquete)
  • __main__.pyno se evalúa para módulos de paquete; el código se evalúa para módulos de código

Ejecución del módulo a través de la línea de comando con nombre de archivo (es decir, python <filename>):

  • sys.pathse modifica para incluir el directorio final en<filename>
  • __name__se establece en'__main__'
  • __package__se establece enNone
  • __init__.pyno se evalúa para ningún paquete (incluido el suyo propio para los módulos del paquete)
  • __main__.pyse evalúa para módulos de paquete; el código se evalúa para módulos de código.

Ejecución del módulo a través de la línea de comando con el nombre del módulo (es decir, python -m <modulename>):

  • sys.pathse modifica para incluir el directorio actual
  • __name__se establece en'__main__'
  • __package__está configurado en el paquete principal inmediato en<modulename>
  • __init__.pyse evalúa para todos los paquetes (incluido el suyo propio para los módulos del paquete)
  • __main__.pyse evalúa para módulos de paquete; el código se evalúa para módulos de código

Conclusión

La -mbandera es, en su forma más simple, un medio para ejecutar scripts de Python desde la línea de comando usando nombres de módulos en lugar de nombres de archivos. Sin embargo, el verdadero poder de -m, está en su capacidad de combinar el poder de importlas declaraciones (por ejemplo, soporte para importaciones relativas explícitas y __init__evaluación automática de paquetes) con la conveniencia de la línea de comando.

Mark Rucker avatar Jul 15 '2020 21:07 Mark Rucker

La primera línea del Rationaleapartado del PEP 338 dice:

Python 2.4 agrega el modificador de línea de comando -m para permitir que los módulos se ubiquen usando el espacio de nombres del módulo Python para su ejecución como scripts. Los ejemplos motivadores fueron módulos de biblioteca estándar como pdb y perfil, y la implementación de Python 2.4 está bien para este propósito limitado.

Por lo tanto, puede especificar cualquier módulo en la ruta de búsqueda de Python de esta manera, no solo los archivos en el directorio actual. Tienes razón, python mymod1.py mymod2.py argstiene exactamente el mismo efecto. La primera línea de la Scope of this proposalsección dice:

En Python 2.4, un módulo ubicado usando -m se ejecuta como si su nombre de archivo se hubiera proporcionado en la línea de comando.

Con -mmás es posible, como trabajar con módulos que son parte de un paquete, etc. De eso se trata el resto de PEP 338. Léelo para más información.

agf avatar Sep 30 '2011 12:09 agf

Vale la pena mencionar que esto sólo funciona si el paquete tiene un archivo.__main__.py De lo contrario, este paquete no se puede ejecutar directamente.

python -m some_package some_arguments

El intérprete de Python buscará un __main__.pyarchivo en la ruta del paquete para ejecutar. Es equivalente a:

python path_to_package/__main__.py somearguments

Ejecutará el contenido después de:

if __name__ == "__main__":
Marquez.Z avatar Dec 14 '2018 02:12 Marquez.Z