Abrir documento con la aplicación del sistema operativo predeterminada en Python, tanto en Windows como en Mac OS

Resuelto Abdullah Jibaly asked hace 15 años • 17 respuestas

Necesito poder abrir un documento usando su aplicación predeterminada en Windows y Mac OS. Básicamente, quiero hacer lo mismo que sucede cuando haces doble clic en el ícono del documento en Explorer o Finder. ¿Cuál es la mejor manera de hacer esto en Python?

Abdullah Jibaly avatar Jan 12 '09 13:01 Abdullah Jibaly
Aceptado

Utilice el subprocessmódulo disponible en Python 2.4+, no os.system(), para no tener que lidiar con el escape del shell.

import subprocess, os, platform
if platform.system() == 'Darwin':       # macOS
    subprocess.call(('open', filepath))
elif platform.system() == 'Windows':    # Windows
    os.startfile(filepath)
else:                                   # linux variants
    subprocess.call(('xdg-open', filepath))

El paréntesis doble se debe a que subprocess.call()quiere una secuencia como primer argumento, por lo que aquí usamos una tupla. En los sistemas Linux con Gnome también hay un gnome-opencomando que hace lo mismo, pero xdg-openes el estándar de Free Desktop Foundation y funciona en entornos de escritorio Linux.

Nick avatar Jan 12 '2009 15:01 Nick

openy startson cosas de intérprete de comandos para Mac OS/X y Windows respectivamente, para hacer esto.

Para llamarlos desde Python, puedes usar subprocessmodule o os.system().

Aquí hay consideraciones sobre qué paquete usar:

  1. Puedes llamarlos a través de os.system, lo cual funciona, pero...

    Escapar: os.system solo funciona con nombres de archivos que no tienen espacios u otros metacaracteres del shell en el nombre de ruta (p. ej. A:\abc\def\a.txt), o de lo contrario es necesario escaparlos. Existe shlex.quotepara sistemas tipo Unix, pero nada realmente estándar para Windows. Quizás vea también Python, Windows: análisis de líneas de comando con shlex

    • Mac OS X:os.system("open " + shlex.quote(filename))
    • Windows: os.system("start " + filename)donde propiamente hablando filenametambién se debe escapar.
  2. También puedes llamarlos vía subprocessmódulo, pero...

    Para Python 2.7 y posteriores, simplemente use

    subprocess.check_call(['open', filename])
    

    En Python 3.5+ puedes usar de manera equivalente el método ligeramente más complejo pero también algo más versátil.

    subprocess.run(['open', filename], check=True)
    

    Si necesita ser compatible desde Python 2.4, puede usar subprocess.call()e implementar su propia verificación de errores:

    try:
        retcode = subprocess.call("open " + filename, shell=True)
        if retcode < 0:
            print >>sys.stderr, "Child was terminated by signal", -retcode
        else:
            print >>sys.stderr, "Child returned", retcode
    except OSError, e:
        print >>sys.stderr, "Execution failed:", e
    

    Ahora bien, ¿cuáles son las ventajas de utilizar subprocess?

    • Seguridad: en teoría, esto es más seguro, pero de hecho necesitamos ejecutar una línea de comando de una forma u otra; en cualquier entorno, necesitamos el entorno y los servicios para interpretar, obtener rutas, etc. En ninguno de los casos estamos ejecutando texto arbitrario, por lo que no tiene un 'filename ; rm -rf /'problema inherente de "pero puedes escribir", y si el nombre del archivo puede estar dañado, usarlo subprocess.callnos brinda poca protección adicional.
    • Manejo de errores: en realidad no nos proporciona más detección de errores, todavía dependemos de retcodeen cualquier caso; pero el comportamiento de generar explícitamente una excepción en el caso de un error ciertamente lo ayudará a notar si hay una falla (aunque en algunos escenarios, un rastreo puede no ser más útil que simplemente ignorar el error).
    • Genera un subproceso (sin bloqueo) : no necesitamos esperar al proceso secundario, ya que, según la declaración del problema, estamos iniciando un proceso separado.

    A la objeción "Pero subprocessse prefiere". Sin embargo, os.system()no está obsoleto y, en cierto sentido, es la herramienta más sencilla para este trabajo en particular. Conclusión: por lo tanto, usar os.system()también es una respuesta correcta.

    Una marcada desventaja es que el startcomando de Windows requiere que usted lo pase, shell=Truelo que anula la mayoría de los beneficios de usar subprocess.

Charlie Martin avatar Jan 12 '2009 06:01 Charlie Martin

Yo prefiero:

os.startfile(path, 'open')

Tenga en cuenta que este módulo admite nombres de archivos que tienen espacios en sus carpetas y archivos, por ejemplo

A:\abc\folder with spaces\file with-spaces.txt

( python docs ) No es necesario agregar 'open' (es el valor predeterminado). Los documentos mencionan específicamente que esto es como hacer doble clic en el ícono de un archivo en el Explorador de Windows.

Esta solución es sólo para Windows.

DrBloodmoney avatar Jan 12 '2009 12:01 DrBloodmoney