Saltar al contenido

python – ¿Cómo se lee en stdin?

octubre 17, 2021
apple touch icon@2

¿Cómo se lee de stdin en Python?

Estoy tratando de hacer algunos de los desafíos de código de golf, pero todos requieren que la entrada se tome de stdin. ¿Cómo consigo eso en Python?

Puedes usar:

  • sys.stdin – Un objeto similar a un archivo – llamar sys.stdin.read() para leer todo.
  • input(prompt) – pasarle un mensaje opcional a la salida, lee desde stdin hasta la primera línea nueva, que elimina. Tendría que hacer esto repetidamente para obtener más líneas, al final de la entrada genera EOFError. (Probablemente no sea bueno para jugar al golf). En Python 2, esto es rawinput(prompt).
  • open(0).read() – En Python 3, la función incorporada open acepta descriptores de archivo (números enteros que representan los recursos de E / S del sistema operativo) y 0 es el descriptor de stdin. Devuelve un objeto similar a un archivo como sys.stdin – probablemente su mejor apuesta para jugar al golf. En Python 2, esto es io.open.
  • open('/dev/stdin').read() – Similar a open(0), funciona en Python 2 y 3, pero no en Windows (ni siquiera en Cygwin).
  • fileinput.input() – devuelve un iterador sobre las líneas en todos los archivos enumerados en sys.argv[1:], o stdin si no se administra. Usar como ''.join(fileinput.input()).

Ambos sys y fileinput deben ser importados, respectivamente, por supuesto.

Rápido sys.stdin ejemplos compatibles con Python 2 y 3, Windows, Unix

Solo necesitas read de sys.stdin, por ejemplo, si canaliza datos a stdin:

$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo

Podemos ver eso sys.stdin está en modo de texto predeterminado:

>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name="<stdin>" mode="r" encoding='UTF-8'>

ejemplo de archivo

Digamos que tienes un archivo inputs.txt, podemos aceptar ese archivo y volver a escribirlo:

python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt

Respuesta más larga

Aquí hay una demostración completa, fácilmente replicable, usando dos métodos, la función incorporada, input (usar raw_input en Python 2), y sys.stdin. Los datos no se modifican, por lo que el procesamiento es una no operación.

Para empezar, creemos un archivo para las entradas:

$ python -c "print('foonbarnbaz')" > inputs.txt

Y usando el código que ya hemos visto, podemos verificar que hemos creado el archivo:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt 
foo
bar
baz

Aquí está la ayuda sobre sys.stdin.read desde Python 3:

read(size=-1, /) method of _io.TextIOWrapper instance
    Read at most n characters from stream.
    
    Read from underlying buffer until we have n characters or we hit EOF.
    If n is negative or omitted, read until EOF.

Función incorporada, input (raw_input en Python 2)

La función incorporada input lee desde la entrada estándar hasta una nueva línea, que se elimina (complementando print, que agrega una nueva línea de forma predeterminada). Esto ocurre hasta que obtiene EOF (Fin de archivo), momento en el que aumenta EOFError.

Por lo tanto, así es como puede usar input en Python 3 (o raw_input en Python 2) para leer desde stdin, por lo que creamos un módulo de Python que llamamos stdindemo.py:

$ python -c "print('try:n    while True:n        print(input())nexcept EOFError:n    pass')" > stdindemo.py 

E imprimámoslo de nuevo para asegurarnos de que sea como esperamos:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py 
try:
    while True:
        print(input())
except EOFError:
    pass

De nuevo, input lee hasta el salto de línea y esencialmente lo quita de la línea. print agrega una nueva línea. Entonces, mientras ambos modifican la entrada, sus modificaciones se cancelan. (Entonces, son esencialmente el complemento de cada uno).

Y cuando input obtiene el carácter de fin de archivo, genera EOFError, que ignoramos y luego salimos del programa.

Y en Linux / Unix, podemos canalizar desde cat:

$ cat inputs.txt | python -m stdindemo
foo
bar
baz

O simplemente podemos redirigir el archivo desde stdin:

$ python -m stdindemo < inputs.txt 
foo
bar
baz

También podemos ejecutar el módulo como script:

$ python stdindemo.py < inputs.txt 
foo
bar
baz

Aquí está la ayuda en el builtin input desde Python 3:

input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.
    
    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.
    
    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.

sys.stdin

Aquí hacemos un script de demostración usando sys.stdin. La forma eficiente de iterar sobre un objeto similar a un archivo es usar el objeto similar a un archivo como un iterador. El método complementario para escribir en stdout desde esta entrada es simplemente usar sys.stdout.write:

$ python -c "print('import sysnfor line in sys.stdin:n    sys.stdout.write(line)')" > stdindemo2.py

Vuelva a imprimirlo para asegurarse de que se vea bien:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py 
import sys
for line in sys.stdin:
    sys.stdout.write(line)

Y redirigiendo las entradas al archivo:

$ python -m stdindemo2 < inputs.txt
foo
bar
baz

Golf en un comando:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz

Descriptores de archivo para golf

Dado que los descriptores de archivo para stdin y stdout son 0 y 1 respectivamente, también podemos pasarlos a open en Python 3 (no 2, y tenga en cuenta que todavía necesitamos la ‘w’ para escribir en stdout).

Si esto funciona en su sistema, eliminará más caracteres.

$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo

Python 2 io.open también hace esto, pero la importación ocupa mucho más espacio:

$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt 
foo
bar
baz

Abordar otros comentarios y respuestas

Un comentario sugiere ''.join(sys.stdin) para jugar al golf, pero en realidad es más largo que sys.stdin.read (); además, Python debe crear una lista adicional en la memoria (así es como str.join funciona cuando no se le da una lista) – para contraste:

''.join(sys.stdin)
sys.stdin.read()

La respuesta principal sugiere:

import fileinput

for line in fileinput.input():
    pass

Pero desde sys.stdin implementa la API de archivos, incluido el protocolo de iterador, que es lo mismo que esto:

import sys

for line in sys.stdin:
    pass

Otra respuesta lo hace sugiero esto. Solo recuerde que si lo hace en un intérprete, deberá hacerlo controlD si está en Linux o Mac, o controlz en Windows (después Ingresar) para enviar el carácter de fin de archivo al proceso. Además, esa respuesta sugiere print(line) – que agrega un 'n' hasta el final – uso print(line, end='') en su lugar (si está en Python 2, necesitará from __future__ import print_function).

El caso de uso real para fileinput es para leer en una serie de archivos.

close