Estou tentando fazer alguns dos desafios do código de golfe , mas todos exigem que a entrada seja retirada stdin
. Como faço para obtê-lo no Python?
Estou tentando fazer alguns dos desafios do código de golfe , mas todos exigem que a entrada seja retirada stdin
. Como faço para obtê-lo no Python?
Respostas:
Você pode usar o fileinput
módulo:
import fileinput
for line in fileinput.input():
pass
fileinput
percorrerá todas as linhas da entrada especificada como nomes de arquivo fornecidos nos argumentos da linha de comandos ou a entrada padrão se nenhum argumento for fornecido.
Nota: line
conterá uma nova linha à direita; para removê-lo useline.rstrip()
Existem algumas maneiras de fazer isso.
sys.stdin
é um objeto parecido com um arquivo no qual você pode chamar funções read
ou readlines
se deseja ler tudo ou se deseja ler tudo e dividi-lo por nova linha automaticamente. (Você precisa que import sys
isso funcione.)
Se você deseja solicitar uma entrada ao usuário, pode usá-lo raw_input
no Python 2.X e apenas input
no Python 3.
Se você realmente quiser apenas ler as opções da linha de comando, poderá acessá-las através da lista sys.argv .
Você provavelmente encontrará este artigo do Wikibook sobre E / S em Python como uma referência útil também.
import sys
for line in sys.stdin:
print(line)
Observe que isso incluirá um caractere de nova linha no final. Para remover a nova linha no final, use line.rstrip()
como @brittohalloran disse.
\r\n
finais de linha
O Python também possui funções internas input()
e raw_input()
. Veja a documentação do Python em Funções internas .
Por exemplo,
name = raw_input("Enter your name: ") # Python 2.x
ou
name = input("Enter your name: ") # Python 3
Aqui está do Learning Python :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
No Unix, você pode testá-lo fazendo algo como:
% cat countlines.py | python countlines.py
Counted 3 lines.
No Windows ou DOS, você faria:
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), '')))
. Vejawc-l.py
cat
aqui é redundante. A chamada correta para sistemas Unix é python countlines.py < countlines.py
.
readlines()
. Objetos de arquivo devem ser iterados sem materializar todos os dados na memória.
Como você lê o stdin em Python?
Estou tentando fazer alguns dos desafios do código de golfe, mas todos exigem que a entrada seja retirada do stdin. Como faço para obtê-lo no Python?
Você pode usar:
sys.stdin
- Um objeto parecido com um arquivo - ligue sys.stdin.read()
para ler tudo.input(prompt)
- passe um prompt opcional para a saída, ele lê do stdin até a primeira nova linha, que é removida. Você teria que fazer isso repetidamente para obter mais linhas; no final da entrada, gera EOFError. (Provavelmente não é bom para jogar golfe.) No Python 2, é isso rawinput(prompt)
.open(0).read()
- No Python 3, a função interna open
aceita descritores de arquivo (números inteiros que representam recursos de E / S do sistema operacional) e 0 é o descritor de stdin
. Ele retorna um objeto parecido com um arquivo como sys.stdin
- provavelmente sua melhor aposta no golfe. No Python 2, é isso io.open
.open('/dev/stdin').read()
- semelhante a open(0)
, funciona em Python 2 e 3, mas não no Windows (ou mesmo no Cygwin).fileinput.input()
- retorna um iterador sobre as linhas em todos os arquivos listados em sys.argv[1:]
, ou stdin, se não for fornecido. Use como ''.join(fileinput.input())
.Ambos sys
e fileinput
devem ser importados, respectivamente, é claro.
sys.stdin
Exemplos rápidos compatíveis com Python 2 e 3, Windows, UnixVocê só precisa read
de sys.stdin
, por exemplo, se os dados de tubulação para stdin:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Podemos ver que sys.stdin
está no modo de texto padrão:
>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
Digamos que você tenha um arquivo, inputs.txt
podemos aceitá-lo e escrevê-lo novamente:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Aqui está uma demonstração completa e facilmente replicável, usando dois métodos, a função embutida input
(uso raw_input
no Python 2) e sys.stdin
. Os dados não são modificados, portanto, o processamento é uma não operação.
Para começar, vamos criar um arquivo para entradas:
$ python -c "print('foo\nbar\nbaz')" > inputs.txt
E usando o código que já vimos, podemos verificar se criamos o arquivo:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Aqui está a ajuda sys.stdin.read
do 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_input
em Python 2)A função incorporada input
lê da entrada padrão até uma nova linha, que é removida (complementando print
, que adiciona uma nova linha por padrão.) Isso ocorre até que receba EOF (Fim do arquivo), momento em que aumenta EOFError
.
Assim, aqui está como você pode usar input
no Python 3 (ou raw_input
no Python 2) para ler a partir de stdin - então criamos um módulo Python que chamamos stdindemo.py:
$ python -c "print('try:\n while True:\n print(input())\nexcept EOFError:\n pass')" > stdindemo.py
E vamos imprimi-lo novamente para garantir que seja como esperamos:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
Novamente, input
lê até a nova linha e retira-a essencialmente da linha. print
adiciona uma nova linha. Portanto, enquanto ambos modificam a entrada, suas modificações são canceladas. (Portanto, eles são essencialmente o complemento um do outro.)
E quando input
obtém o caractere de fim de arquivo, gera EOFError, que ignoramos e saímos do programa.
E no Linux / Unix, podemos canalizar do gato:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
Ou podemos apenas redirecionar o arquivo do stdin:
$ python -m stdindemo < inputs.txt
foo
bar
baz
Também podemos executar o módulo como um script:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Aqui está a ajuda sobre o built-in input
do 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
Aqui nós fazemos um script de demonstração usando sys.stdin
. A maneira eficiente de iterar sobre um objeto semelhante a arquivo é usar o objeto semelhante a arquivo como um iterador. O método complementar para escrever no stdout a partir desta entrada é simplesmente usar sys.stdout.write
:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Imprima-o novamente para garantir a aparência correta:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py
import sys
for line in sys.stdin:
sys.stdout.write(line)
E redirecionando as entradas para o arquivo:
$ python -m stdindemo2 < inputs.txt
foo
bar
baz
Golfed em um comando:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Como os descritores de arquivo para stdin
e stdout
são 0 e 1, respectivamente, também podemos transmiti-los para o open
Python 3 (não 2, e observe que ainda precisamos do 'w' para escrever no stdout).
Se isso funcionar no seu sistema, ele eliminará mais caracteres.
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
O Python 2 também io.open
faz isso, mas a importação ocupa muito mais espaço:
$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt
foo
bar
baz
Um comentário sugere ''.join(sys.stdin)
para jogar golfe, mas na verdade é mais longo que sys.stdin.read () - além disso, o Python deve criar uma lista extra na memória (é assim que str.join
funciona quando não é fornecida uma lista) - para contraste:
''.join(sys.stdin)
sys.stdin.read()
A resposta principal sugere:
import fileinput
for line in fileinput.input():
pass
Mas, como sys.stdin
implementa a API do arquivo, incluindo o protocolo do iterador, é o mesmo:
import sys
for line in sys.stdin:
pass
Outra resposta que sugerem isso. Lembre-se de que, se você fizer isso em um intérprete, precisará fazer isso Ctrl- dse estiver no Linux ou Mac ou Ctrl- zno Windows (depois Enter) para enviar o caractere de fim de arquivo ao processo. Além disso, essa resposta sugere print(line)
- que adiciona um '\n'
ao final - use print(line, end='')
(em Python 2, você precisará from __future__ import print_function
).
O caso de uso real para fileinput
é para ler em uma série de arquivos.
A resposta proposta por outros:
for line in sys.stdin:
print line
é muito simples e pitônico, mas deve-se notar que o script aguardará até o EOF antes de começar a iterar nas linhas de entrada.
Isso significa que tail -f error_log | myscript.py
não processará as linhas conforme o esperado.
O script correto para esse caso de uso seria:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
ATUALIZAÇÃO
A partir dos comentários, foi esclarecido que somente no python 2 pode haver buffer envolvido, para que você espere que o buffer seja preenchido ou EOF antes da emissão da chamada de impressão.
for line in sys.stdin:
padrão não espera pelo EOF. Mas se você testar em arquivos muito pequenos, as respostas poderão ficar em buffer. Teste com mais dados para ver se ele lê resultados intermediários.
print line
não acordou no 3.1.3, mas print(line)
sim.
for line in sys.stdin:
não "bloqueia até EOF". Há um bug de leitura antecipada no Python 2 que atrasa as linhas até que o buffer correspondente esteja cheio. É um problema de buffer não relacionado ao EOF. Para solução alternativa, use for line in iter(sys.stdin.readline, ''):
(use io.open()
para arquivos comuns). Você não precisa dele em Python 3.
Com base em todas as respostas que sys.stdin
você usa , você também pode fazer algo como o seguinte para ler um arquivo de argumento, se pelo menos um argumento existir, e voltar ao stdin caso contrário:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
e use-o como
$ python do-my-stuff.py infile.txt
ou
$ cat infile.txt | python do-my-stuff.py
ou mesmo
$ python do-my-stuff.py < infile.txt
Isso faria seu script Python se comportar como muitos programas GNU / Unix, como cat
, grep
e sed
.
argparse
é uma solução fácilExemplo compatível com as versões 2 e 3 do 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()
Você pode executar este script de várias maneiras:
1. Usando stdin
echo 'foo bar' | ./above-script.py
ou mais curto, substituindo echo
por aqui string :
./above-script.py <<< 'foo bar'
2. Usando um argumento de nome de arquivo
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Usando stdin
através do nome de arquivo especial-
echo 'foo bar' | ./above-script.py -
add_argument('--in'
e, em seguida, canalizar para o script e adicionar --in -
à linha de comando. PS in
não é um nome muito bom para uma variável / atributo.
in
não é apenas um nome ruim para uma variável, é ilegal. args.in.read()
irá gerar o erro InvalidSyntax devido à in
palavra-chave reservada. Pode simplesmente mudar o nome para infile
gostar do que os documentos do python argparse fazem: docs.python.org/3/library/…
O seguinte chip de código o ajudará (ele lerá todos os stdin bloqueando até EOF
em uma sequência):
import sys
input_str = sys.stdin.read()
print input_str.split()
Estou bastante surpreso que ninguém tenha mencionado esse hack até agora:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
em python2, você pode interromper a set()
chamada, mas pode dizer o que quer que seja
readlines
que usar essa divisão em linhas e depois join
novamente? Você pode simplesmente escreverprint(sys.stdin.read())
write
retorna None
, e o tamanho do conjunto nunca seria maior que 1 ( =len(set([None]))
)
Você pode ler do stdin e, em seguida, armazenar entradas em "dados" da seguinte maneira:
data = ""
for line in sys.stdin:
data += line
data = sys.stdin.read()
, sem o problema de concatenações de sequência repetidas.
Leia a partir sys.stdin
, mas para ler dados binários no Windows , você precisa ter cuidado extra, pois sys.stdin
ele é aberto no modo de texto e ele será corrompido ao ser \r\n
substituído \n
.
A solução é definir o modo como binário se o Windows + Python 2 for detectado e no 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()
Eu uso o método a seguir, ele retorna uma string de stdin (eu uso para a análise de json). Funciona com pipe e prompt no Windows (ainda não testado no Linux). Quando solicitado, duas quebras de linha indicam o fim da 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
O problema que tenho com solução
import sys
for line in sys.stdin:
print(line)
é que, se você não passar nenhum dado para o stdin, ele será bloqueado para sempre. É por isso que adoro esta resposta : verifique se há alguns dados sobre stdin primeiro e depois leia-os. Isto é o que acabei fazendo:
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)
select
for chamada; ou você também pode enfrentar problemas se o stdin estiver conectado a um arquivo em uma mídia lenta (rede, CD, fita etc.). Você disse que "se você não passar nenhum dado para o stdin, ele será bloqueado para sempre". é um problema , mas eu diria que é um recurso . A maioria dos programas CLI (por exemplo cat
) funciona dessa maneira, e espera-se que eles funcionem. EOF é a única coisa da qual você deve confiar para detectar o final da entrada.
Eu tive alguns problemas ao fazer isso funcionar para a leitura de soquetes canalizados para ele. Quando o soquete foi fechado, ele começou a retornar uma string vazia em um loop ativo. Portanto, esta é minha solução (que eu testei apenas no Linux, mas espero que funcione em todos os outros sistemas)
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Portanto, se você começar a ouvir em um soquete, ele funcionará corretamente (por exemplo, no bash):
while :; do nc -l 12345 | python test.py ; done
E você pode chamá-lo com telnet ou apenas apontar um navegador para localhost: 12345
Em relação a este:
for line in sys.stdin:
Eu apenas tentei no python 2.7 (seguindo a sugestão de outra pessoa) para um arquivo muito grande, e não o recomendo, exatamente pelas razões mencionadas acima (nada acontece por um longo tempo).
Acabei com uma solução um pouco mais pitônica (e funciona em arquivos maiores):
with open(sys.argv[1], 'r') as f:
for line in f:
Então eu posso executar o 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.stdin
como argumento da linha de comando para o script.
sys.stdin
como argumento da linha de comando para o script? Argumentos são sequências e fluxos são objetos semelhantes a arquivos, não são os mesmos.
sys.stdin
é um arquivo-como objeto
Para Python 3, isso seria:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Esta é basicamente uma forma simples de cat (1), pois não adiciona uma nova linha após cada linha. Você pode usar isso (depois de marcar o arquivo executável usando chmod +x cat.py
:
echo Hello | ./cat.py
Ao usar o -c
comando, de uma maneira complicada, em vez de ler o stdin
(e mais flexível em alguns casos), você também pode passar um comando de script de shell para o seu comando python colocando o comando de venda entre aspas entre parênteses, iniciado por $
sign.
por exemplo
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Contará o número de linhas do arquivo de histórico do goldendict.