O buffer de saída está ativado por padrão no intérprete do Python para sys.stdout
?
Se a resposta for positiva, quais são as formas de desativá-la?
Sugestões até agora:
- Use a
-u
opção de linha de comando - Envolver
sys.stdout
um objeto que libere após cada gravação - Definir
PYTHONUNBUFFERED
env var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Existe alguma outra maneira de definir algum sinalizador global sys
/ sys.stdout
programaticamente durante a execução?
-u
é que ele não funcionará para código de código compilado ou para aplicativos com um__main__.py
arquivo como ponto de entrada.Respostas:
De Magnus Lycka, responda em uma lista de discussão :
fonte
#!/usr/bin/env python -u
não funciona !! veja aqui__getattr__
só para evitar herança ?!iter()
em vez dowhile
loop:for line in iter(pipe.readline, ''):
. Você não precisa dele no Python 3, ondefor line in pipe:
produz o mais rápido possível.Prefiro colocar minha resposta em Como liberar a saída da função de impressão? ou na função de impressão do Python que libera o buffer quando é chamado? , mas como foram marcados como duplicados (o que não concordo), responderei aqui.
Desde o Python 3.3, print () suporta o argumento da palavra-chave "flush" ( consulte a documentação ):
fonte
Créditos: "Sebastian", em algum lugar da lista de discussão em Python.
fonte
flush=True
parâmetro paraprint()
funcionar desde o Python 3.3.os.fdopen(sys.stdout.fileno(), 'wb', 0)
(observe ob
para binário) eflush=True
trabalhem para mim em 3.6.4. No entanto, se você estiver usando o subprocesso para iniciar outro script, verifique se especificoupython3
se possui várias instâncias do python instaladas.os.fdopen(sys.stdout.fileno(), 'wb', 0)
você acaba com um objeto de arquivo binário, não com umTextIO
fluxo. Você precisaria adicionar umTextIOWrapper
ao mix (certifique-se de ativarwrite_through
a eliminação de todos os buffers ou useline_buffering=True
apenas para liberar novas linhas).Sim, ele é.
Você pode desativá-lo na linha de comando com a opção "-u".
Como alternativa, você pode chamar .flush () no sys.stdout em cada gravação (ou agrupá-lo com um objeto que faça isso automaticamente)
fonte
Isso está relacionado à resposta de Cristóvão D. Sousa, mas ainda não pude comentar.
Uma maneira direta de usar o
flush
argumento de palavra - chave do Python 3 para sempre ter saída sem buffer é:depois, a impressão sempre liberará a saída diretamente (exceto se
flush=False
for fornecido).Observe que (a) isso responde apenas parcialmente à pergunta, pois não redireciona toda a saída. Mas eu acho que
print
é a maneira mais comum de criar saída parastdout
/stderr
em python, portanto essas duas linhas cobrem provavelmente a maioria dos casos de uso.Observe (b) que ele funciona apenas no módulo / script em que você o definiu. Isso pode ser bom ao escrever um módulo, pois não mexe com o
sys.stdout
.O Python 2 não fornece o
flush
argumento, mas você pode emular umaprint
função do tipo Python 3, conforme descrito aqui https://stackoverflow.com/a/27991478/3734258 .fonte
flush
kwarg no python2.Sem salvar o sys.stdout antigo, disable_stdout_buffering () não é idempotente e várias chamadas resultarão em um erro como este:
Outra possibilidade é:
(Anexar ao gc.garbage não é uma boa idéia, pois é onde os ciclos não-viáveis são colocados, e você pode procurar por eles.)
fonte
stdout
ainda vivesys.__stdout__
como alguns sugeriram, a coisa do lixo não será necessária, certo? É um truque legal, no entanto.ValueError: can't have unbuffered text I/O
ao chamarprint()
.O seguinte funciona no Python 2.6, 2.7 e 3.2:
fonte
OSError: [Errno 29] Illegal seek
para a linhasys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
Sim, está ativado por padrão. Você pode desativá-lo usando a opção -u na linha de comando ao chamar python.
fonte
Você também pode executar o Python com o utilitário stdbuf :
stdbuf -oL python <script>
fonte
-oL
habilitado) ainda está em buffer - consulte f / e stackoverflow.com/questions/58416853/… , perguntando porend=''
que a saída não é mais exibida imediatamente.print(..., end='', flush=True)
onde isso é improtante? OTOH, quando vários programas gravam na mesma saída simultaneamente, o trade-off tende a mudar de um progresso imediato para a redução de misturas de saída, e o buffer de linha se torna atraente. Então, talvez seja melhor não escrever explícitoflush
e controlar o buffer externamente?flush
. O controle de buffer externo é uma solução alternativaNo Python 3, você pode aplicar um patch de macaco na função de impressão, para sempre enviar flush = True:
Conforme indicado em um comentário, você pode simplificar isso vinculando o parâmetro flush a um valor, via
functools.partial
:fonte
functools.partial
?print = functools.partial(print, flush=True)
funciona bem para mim.import builtins; builtins.print = partial(print, flush=True)
Você também pode usar o fcntl para alterar os sinalizadores de arquivo rapidamente.
fonte
É possível substituir apenas o
write
método desys.stdout
um que chamaflush
. A implementação do método sugerido está abaixo.O valor padrão do
w
argumento manterá awrite
referência do método original . Depois dewrite_flush
definido, o originalwrite
pode ser substituído.O código assume que
stdout
é importado dessa maneirafrom sys import stdout
.fonte
Você pode criar um arquivo sem buffer e atribuir esse arquivo a sys.stdout.
Você não pode alterar magicamente o stdout fornecido pelo sistema; desde que ele seja fornecido ao seu programa python pelo sistema operacional.
fonte
Variante que funciona sem travar (pelo menos no win32; python 2.7, ipython 0.12) e depois chamada posteriormente (várias vezes):
fonte
sys.stdout is sys.__stdout__
vez de confiar no objeto de substituição que possui um atributo de nome?(Eu publiquei um comentário, mas ele se perdeu de alguma forma. Então, novamente :)
Como notei, o CPython (pelo menos no Linux) se comporta de maneira diferente, dependendo de onde a saída vai. Se for para tty, a saída será liberada após cada '
\n'
Se for para um tubo / processo, será armazenada em buffer e você poderá usar as
flush()
soluções baseadas ou a opção -u recomendada acima.Ligeiramente relacionado ao buffer de saída:
se você iterar nas linhas na entrada com
for line in sys.stdin:
...
então a implementação for no CPython coletará a entrada por um tempo e, em seguida, executará o corpo do loop para várias linhas de entrada. Se o seu script estiver prestes a gravar a saída para cada linha de entrada, isso pode parecer um buffer de saída, mas na verdade é um lote e, portanto, nenhuma das
flush()
técnicas etc. ajudará isso. Curiosamente, você não tem esse comportamento no pypy . Para evitar isso, você pode usarwhile True: line=sys.stdin.readline()
...
fonte
for line in sys.stdin
vsfor line in iter(sys.stdin.readline, "")
for line in sys.stdin
fornece uma resposta atrasada)Uma maneira de obter saída sem buffer seria usar em
sys.stderr
vez desys.stdout
ou simplesmente chamarsys.stdout.flush()
para forçar explicitamente uma gravação a ocorrer.Você pode redirecionar facilmente tudo impresso fazendo:
Ou para redirecionar apenas para uma
print
instrução específica :Para redefinir o stdout, você pode simplesmente fazer:
fonte