Estoy tratando de hacer algunos de los desafíos del código de golf , pero todos requieren que se tome la entrada stdin. ¿Cómo consigo eso en Python?
Estoy tratando de hacer algunos de los desafíos del código de golf , pero todos requieren que se tome la entrada stdin. ¿Cómo consigo eso en Python?
Respuestas:
Podrías usar el fileinputmódulo:
import fileinput
for line in fileinput.input():
pass
fileinput recorrerá todas las líneas en la entrada especificada como nombres de archivo dados en argumentos de línea de comandos, o la entrada estándar si no se proporcionan argumentos.
Nota: linecontendrá una nueva línea final; para eliminarlo useline.rstrip()
Hay algunas formas de hacerlo.
sys.stdines un objeto similar a un archivo en el que puede llamar funciones reado readlinessi desea leer todo o si desea leer todo y dividirlo por nueva línea automáticamente. (Es necesario que import sysesto funcione).
Si desea solicitar al usuario una entrada, puede usarla raw_inputen Python 2.X y solo inputen Python 3.
Si en realidad solo desea leer las opciones de la línea de comandos, puede acceder a ellas a través de la lista sys.argv .
Probablemente encontrará que este artículo de Wikibook sobre E / S en Python también es una referencia útil.
import sys
for line in sys.stdin:
print(line)
Tenga en cuenta que esto incluirá un carácter de nueva línea al final. Para eliminar la nueva línea al final, use line.rstrip()como dijo @brittohalloran.
\r\nlos finales de línea
Python también tiene funciones integradas input()y raw_input(). Consulte la documentación de Python en Funciones incorporadas .
Por ejemplo,
name = raw_input("Enter your name: ") # Python 2.x
o
name = input("Enter your name: ") # Python 3
Aquí está de Learning Python :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
En Unix, puede probarlo haciendo algo como:
% cat countlines.py | python countlines.py
Counted 3 lines.
En Windows o DOS, harías:
C:\> type countlines.py | python countlines.py
Counted 3 lines.
print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), ''))). verwc-l.py
cataquí es redundante. La invocación correcta para sistemas Unix es python countlines.py < countlines.py.
readlines(). Los objetos de archivo están destinados a ser iterados sin materializar todos los datos en la memoria.
¿Cómo se lee desde stdin en Python?
Estoy tratando de hacer algunos de los desafíos del 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: llame sys.stdin.read()para leer todo.input(prompt)- pásele un mensaje opcional para generar, 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 aumenta EOFError. (Probablemente no es genial para jugar al golf.) En Python 2, esto es rawinput(prompt).open(0).read()- En Python 3, la función incorporada openacepta descriptores de archivo (enteros que representan recursos de E / S del sistema operativo) y 0 es el descriptor de stdin. Devuelve un objeto similar a un archivo 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 (o incluso Cygwin).fileinput.input()- devuelve un iterador sobre líneas en todos los archivos enumerados sys.argv[1:], o stdin si no se proporciona. Utilizar como ''.join(fileinput.input()).Ambos sysy fileinputdeben importarse, respectivamente, por supuesto.
sys.stdinEjemplos rápidos compatibles con Python 2 y 3, Windows, UnixSólo tiene que readpartir sys.stdin, por ejemplo, si los datos de tubería a la entrada estándar:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Podemos ver que sys.stdinestá en modo de texto predeterminado:
>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
Digamos que tiene un archivo, inputs.txtpodemos aceptar ese archivo y volver a escribirlo:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Aquí hay una demostración completa, fácilmente replicable, usando dos métodos, la función incorporada, input(uso raw_inputen Python 2) y sys.stdin. Los datos no se modifican, por lo que el procesamiento no funciona.
Para empezar, creemos un archivo para entradas:
$ python -c "print('foo\nbar\nbaz')" > 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 sys.stdin.readde 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.
input( raw_inputen Python 2)La función incorporada inputlee desde la entrada estándar hasta una nueva línea, que se elimina (complementando print, lo que agrega una nueva línea por defecto). Esto ocurre hasta que obtiene EOF (Fin del archivo), momento en el que se eleva EOFError.
Por lo tanto, así es como puede usar inputen Python 3 (o raw_inputen 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
Y imprimámoslo nuevamente para asegurarnos de que es como esperamos:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
Nuevamente, inputlee hasta la nueva línea y esencialmente la elimina de la línea. printagrega una nueva línea. Entonces, mientras ambos modifican la entrada, sus modificaciones se cancelan. (Por lo tanto, son esencialmente el complemento del otro).
Y cuando inputobtiene 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 un script:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Aquí está la ayuda sobre la construcción inputde 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.stdinAquí 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 iterador. El método complementario para escribir en stdout desde esta entrada es simplemente usar sys.stdout.write:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Imprima de nuevo para asegurarse de que se ve 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
Golfed en un comando:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Dado que los descriptores de archivo para stdiny stdoutson 0 y 1 respectivamente, también podemos pasarlos a openPython 3 (no a 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 también io.openhace 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
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.joinfunciona cuando no se le da una lista), por contraste:
''.join(sys.stdin)
sys.stdin.read()
La respuesta principal sugiere:
import fileinput
for line in fileinput.input():
pass
Pero, dado que sys.stdinimplementa la API de archivo, incluido el protocolo de iterador, es lo mismo que esto:
import sys
for line in sys.stdin:
pass
Otra respuesta no sugiere esto. Sólo recuerde que si lo hace en un intérprete, usted tiene que hacer Ctrl- dsi estás en Linux o Mac, o Ctrl- zen Windows (después Enter) para enviar el carácter de fin de archivo en el proceso. Además, esa respuesta sugiere print(line), que agrega una '\n'al final, usar print(line, end='')en su lugar (si en Python 2, necesitará from __future__ import print_function).
El caso de uso real fileinputes para leer en una serie de archivos.
La respuesta propuesta por otros:
for line in sys.stdin:
print line
es muy simple y pitónico, pero debe tenerse en cuenta que el script esperará hasta EOF antes de comenzar a iterar en las líneas de entrada.
Esto significa que tail -f error_log | myscript.pyno procesará líneas como se esperaba.
El script correcto para tal caso de uso sería:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
ACTUALIZACIÓN
De los comentarios se ha aclarado que en python 2 solo puede haber un búfer involucrado, por lo que terminará esperando que se llene el búfer o EOF antes de que se emita la llamada de impresión.
for line in sys.stdin:patrón no espera EOF. Pero si prueba en archivos muy pequeños, las respuestas se pueden almacenar. Pruebe con más datos para ver que lee resultados intermedios.
print lineno se despertó en 3.1.3, pero print(line)sí.
for line in sys.stdin:no "bloquea hasta EOF". Hay un error de lectura anticipada en Python 2 que retrasa las líneas hasta que el búfer correspondiente esté lleno. Es un problema de almacenamiento en búfer que no está relacionado con EOF. Para solucionarlo, use for line in iter(sys.stdin.readline, ''):(use io.open()para archivos ordinarios). No lo necesitas en Python 3.
Sobre la base de todas las respuestas usando sys.stdin, también puede hacer algo como lo siguiente para leer desde un archivo de argumentos si existe al menos un argumento, y recurrir a stdin de lo contrario:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
y úsalo como
$ python do-my-stuff.py infile.txt
o
$ cat infile.txt | python do-my-stuff.py
o incluso
$ python do-my-stuff.py < infile.txt
Eso haría que su script Python se comportara como muchos programas GNU / Unix como cat, grepy sed.
argparse es una solución fácilEjemplo compatible con las versiones 2 y 3 de Python:
#!/usr/bin/python
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument('infile',
default=sys.stdin,
type=argparse.FileType('r'),
nargs='?')
args = parser.parse_args()
data = args.infile.read()
Puede ejecutar este script de muchas maneras:
1. Usando stdin
echo 'foo bar' | ./above-script.py
o más corto reemplazando echopor cadena aquí :
./above-script.py <<< 'foo bar'
2. Usando un argumento de nombre de archivo
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Usando a stdintravés del nombre de archivo especial-
echo 'foo bar' | ./above-script.py -
add_argument('--in'y luego canalizar al script y agregarlo --in -a la línea de comando. PS inno es un muy buen nombre para una variable / atributo.
inno es solo un mal nombre para una variable, es ilegal. args.in.read()generará un error InvalidSyntax debido a la inpalabra clave reservada. Simplemente puede cambiar el nombre para infilegustar los documentos de discusión de python do: docs.python.org/3/library/…
El siguiente chip de código lo ayudará (leerá todo el bloqueo de stdin EOFen una sola cadena):
import sys
input_str = sys.stdin.read()
print input_str.split()
Estoy bastante sorprendido de que nadie haya mencionado este truco hasta ahora:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
en python2 puede soltar la set()llamada, pero sería de cualquier manera
readlinesesa división en líneas y luego joinotra vez? Puedes escribirprint(sys.stdin.read())
writeregresa None, y el tamaño establecido nunca sería mayor que 1 ( =len(set([None])))
Puede leer desde stdin y luego almacenar entradas en "datos" de la siguiente manera:
data = ""
for line in sys.stdin:
data += line
data = sys.stdin.read()sin el problema de las concatenaciones de cadenas repetidas.
Leer desde sys.stdin, pero para leer datos binarios en Windows , debe tener mucho cuidado, ya sys.stdinque se abre en modo texto y se dañará al \r\nreemplazarlos \n.
La solución es establecer el modo en binario si se detecta Windows + Python 2, y en Python 3 usar sys.stdin.buffer.
import sys
PY3K = sys.version_info >= (3, 0)
if PY3K:
source = sys.stdin.buffer
else:
# Python 2 on Windows opens sys.stdin in text mode, and
# binary data that read from it becomes corrupted on \r\n
if sys.platform == "win32":
# set sys.stdin to binary mode
import os, msvcrt
msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
source = sys.stdin
b = source.read()
Uso el siguiente método, devuelve una cadena de stdin (lo uso para el análisis json). Funciona con pipe y prompt en Windows (aún no se ha probado en Linux). Cuando se le solicita, dos saltos de línea indican el final de la entrada.
def get_from_stdin():
lb = 0
stdin = ''
for line in sys.stdin:
if line == "\n":
lb += 1
if lb == 2:
break
else:
lb = 0
stdin += line
return stdin
El problema que tengo con la solucion
import sys
for line in sys.stdin:
print(line)
es que si no pasa ningún dato a stdin, se bloqueará para siempre. Es por eso que me encanta esta respuesta : primero verifique si hay algunos datos en stdin y luego léala. Esto es lo que terminé haciendo:
import sys
import select
# select(files to read from, files to write to, magic, timeout)
# timeout=0.0 is essential b/c we want to know the asnwer right away
if select.select([sys.stdin], [], [], 0.0)[0]:
help_file_fragment = sys.stdin.read()
else:
print("No data passed to stdin", file=sys.stderr)
sys.exit(2)
selectse llama; o también podría enfrentar problemas si stdin está conectado a un archivo en un medio lento (red, CD, cinta, etc.). Dijiste que "si no pasas ningún dato a stdin, se bloqueará para siempre". es un problema , pero yo diría que es una característica . La mayoría de los programas CLI (por ejemplo cat) funcionan de esta manera, y se espera que lo hagan. EOF es lo único en lo que debe depender para detectar el final de la entrada.
Tuve algunos problemas al hacer que esto funcionara para leer sobre sockets conectados a él. Cuando el zócalo se cerró, comenzó a devolver una cadena vacía en un bucle activo. Así que esta es mi solución (que solo probé en Linux, pero espero que funcione en todos los demás sistemas)
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Entonces, si comienza a escuchar en un socket, funcionará correctamente (por ejemplo, en bash):
while :; do nc -l 12345 | python test.py ; done
Y puede llamarlo con telnet o simplemente apuntar un navegador a localhost: 12345
Con respecto a este:
for line in sys.stdin:
Acabo de probarlo en Python 2.7 (siguiendo la sugerencia de otra persona) para un archivo muy grande, y no lo recomiendo, precisamente por las razones mencionadas anteriormente (no pasa nada durante mucho tiempo).
Terminé con una solución un poco más pitónica (y funciona en archivos más grandes):
with open(sys.argv[1], 'r') as f:
for line in f:
Entonces puedo ejecutar el script localmente como:
python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work
sys.stdincomo argumento de línea de comandos al script.
sys.stdincomo un argumento de línea de comandos al script? Los argumentos son cadenas y las secuencias son objetos en forma de archivo, no son lo mismo.
sys.stdines un objeto similar a un archivo
Para Python 3 eso sería:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Esta es básicamente una forma simple de cat (1), ya que no agrega una nueva línea después de cada línea. Puede usar esto (después de haber marcado el archivo ejecutable usando chmod +x cat.py:
echo Hello | ./cat.py
Al usar el -ccomando, como una forma complicada, en lugar de leer el stdin(y más flexible en algunos casos), también puede pasar un comando de script de shell a su comando de Python poniendo el comando de venta entre comillas dentro de un paréntesis que comienza con un $signo.
p.ej
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Esto contará el número de líneas del archivo histórico de goldendict.