Czy buforowanie danych wyjściowych jest domyślnie włączone dla interpretera Pythona sys.stdout
?
Jeśli odpowiedź jest pozytywna, jakie są wszystkie sposoby jej wyłączenia?
Dotychczasowe sugestie:
- Użyj
-u
przełącznika wiersza polecenia - Zawiń
sys.stdout
w obiekt, który opróżnia się po każdym zapisie - Ustaw
PYTHONUNBUFFERED
env var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Czy jest jakiś inny sposób na ustawienie globalnej flagi sys
/ sys.stdout
programowo podczas wykonywania?
-u
jest to, że nie będzie działać w przypadku skompilowanego kodu bajtowego lub aplikacji z__main__.py
plikiem jako punktem wejścia.Odpowiedzi:
Od Magnusa Lycki odpowiedź na liście mailingowej :
źródło
#!/usr/bin/env python -u
nie działa !! patrz tutaj__getattr__
żeby uniknąć dziedziczenia ?!iter()
zamiastwhile
pętli:for line in iter(pipe.readline, ''):
. Nie potrzebujesz go w Pythonie 3, gdziefor line in pipe:
daje to tak szybko, jak to możliwe.Wolę umieścić odpowiedź w Jak opróżnić wyjście funkcji drukowania? lub w funkcji drukowania Pythona, która opróżnia bufor, gdy jest wywoływany? , ale ponieważ zostały oznaczone jako duplikaty tego (czego się nie zgadzam), odpowiem tutaj.
Od wersji Python 3.3 print () obsługuje argument słowa kluczowego „flush” ( patrz dokumentacja ):
źródło
Kredyty: „Sebastian”, gdzieś na liście dyskusyjnej Python.
źródło
flush=True
parametr doprint()
działania od wersji Python 3.3.os.fdopen(sys.stdout.fileno(), 'wb', 0)
(zwróć uwagęb
na binarne), jak iflush=True
praca dla mnie w 3.6.4. Jeśli jednak używasz podprocesu do uruchomienia innego skryptu, upewnij się, że podałeśpython3
, jeśli masz zainstalowanych wiele instancji Pythona.os.fdopen(sys.stdout.fileno(), 'wb', 0)
, skończysz z obiektem pliku binarnego, a nie zeTextIO
strumieniem. Trzeba by dodaćTextIOWrapper
miks (upewniając się, żewrite_through
można wyeliminować wszystkie bufory lub użyćline_buffering=True
tylko do koloru na nowych liniach).Tak to jest.
Możesz go wyłączyć w wierszu polecenia za pomocą przełącznika „-u”.
Alternatywnie możesz wywołać .flush () na sys.stdout przy każdym zapisie (lub owinąć go obiektem, który robi to automatycznie)
źródło
Odnosi się to do odpowiedzi Cristóvão D. Sousy, ale nie mogłem jeszcze komentować.
Prosty sposób użycia
flush
argumentu słowa kluczowego w Pythonie 3 , aby zawsze mieć niebuforowane dane wyjściowe, jest:potem wydruk zawsze będzie bezpośrednio wylewał wydruk (z wyjątkiem tego, że
flush=False
podano).Zauważ, (a), że to odpowiada tylko częściowo na pytanie, ponieważ nie przekierowuje wszystkich wyników. Ale przypuszczam
print
wydaje jest to najczęstszy sposób tworzenia danych wyjściowych dostdout
/stderr
w pythonie, więc te 2 linie obejmują prawdopodobnie większość przypadków użycia.Uwaga (b), że działa tylko w module / skrypcie, w którym został zdefiniowany. Może to być dobre podczas pisania modułu, ponieważ nie zadziera z
sys.stdout
.Python 2 nie podaje
flush
argumentu, ale możesz emulować funkcję typu Python 3,print
jak opisano tutaj https://stackoverflow.com/a/27991478/3734258 .źródło
flush
w python2 nie ma kwarga.Bez zapisania starego sys.stdout funkcja disable_stdout_buffering () nie jest idempotentna, a wiele wywołań spowoduje błąd taki jak ten:
Inną możliwością jest:
(Dołączanie do gc.garbage nie jest dobrym pomysłem, ponieważ tam umieszczane są cykle niemożliwe do zniesienia i możesz je sprawdzić).
źródło
stdout
nadal żyje,sys.__stdout__
jak sugerują niektórzy, śmieci nie będą konieczne, prawda? To fajna sztuczka.ValueError: can't have unbuffered text I/O
podczas wywoływaniaprint()
.Poniższe działa w Pythonie 2.6, 2.7 i 3.2:
źródło
OSError: [Errno 29] Illegal seek
linięsys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
Tak, jest domyślnie włączony. Możesz go wyłączyć, używając opcji -u w wierszu poleceń podczas wywoływania Pythona.
źródło
Możesz również uruchomić Python za pomocą narzędzia stdbuf :
stdbuf -oL python <script>
źródło
-oL
włączone) jest nadal buforowane - patrz f / e stackoverflow.com/questions/58416853/... , pytając, dlaczegoend=''
wyjście nie jest natychmiast wyświetlane.print(..., end='', flush=True)
gdzie jest to niepraktyczne? OTOH, gdy kilka programów jednocześnie pisze na tym samym wyjściu, kompromis ma tendencję do przechodzenia od natychmiastowego postępu do zmniejszania pomieszania wyników, a buforowanie linii staje się atrakcyjne. Więc może to lepiej nie pisać jawneflush
i kontrola buforowanie zewnętrznie?flush
. Zewnętrzne sterowanie buforowaniem jest tutajW Pythonie 3 możesz małpować łatanie funkcji drukowania, aby zawsze wysyłać flush = True:
Jak wskazano w komentarzu, można to uprościć, wiążąc parametr flush z wartością za pomocą
functools.partial
:źródło
functools.partial
?print = functools.partial(print, flush=True)
działa dobrze dla mnie.import builtins; builtins.print = partial(print, flush=True)
Możesz także użyć fcntl, aby zmienić flagi plików w locie.
źródło
Możliwe jest zastąpienie tylko
write
metodysys.stdout
z tą, która wywołujeflush
. Sugerowana implementacja metody znajduje się poniżej.Domyślna wartość
w
argumentu zachowa oryginalnewrite
odniesienie do metody. Powrite_flush
zdefiniowaniu oryginałwrite
może zostać zastąpiony.Kod zakłada, że
stdout
jest importowany w ten sposóbfrom sys import stdout
.źródło
Możesz utworzyć niebuforowany plik i przypisać ten plik do sys.stdout.
Nie można magicznie zmienić standardowego wejścia dostarczonego przez system; ponieważ jest dostarczany do twojego programu python przez system operacyjny.
źródło
Wariant, który działa bez awarii (przynajmniej w win32; python 2.7, ipython 0.12), a następnie wywoływany (wielokrotnie):
źródło
sys.stdout is sys.__stdout__
zamiast polegać na zamiennym obiekcie posiadającym atrybut nazwy?(Opublikowałem komentarz, ale jakoś się zgubił. Więc jeszcze raz :)
Jak zauważyłem, CPython (przynajmniej w Linuksie) zachowuje się inaczej w zależności od tego, gdzie idzie wyjście. Jeśli przejdzie do tty, dane wyjściowe są opróżniane po każdym '
\n'
Jeśli przejdzie do potoku / procesu, jest buforowany i można użyć
flush()
rozwiązań bazowych lub opcji -u zalecanej powyżej.Nieznacznie związane z buforowaniem danych wyjściowych:
jeśli iterujesz po liniach wejścia za pomocą
for line in sys.stdin:
...
wówczas za wdrażanie w CPython będzie zbierać dane wejściowe na chwilę, a następnie wykonać ciało pętli za bandą liniach wejściowych. Jeśli twój skrypt ma zamiar zapisać dane wyjściowe dla każdego wiersza wejściowego, może to wyglądać jak buforowanie danych wyjściowych, ale w rzeczywistości jest ono grupowe, a zatem żadna z
flush()
technik itp. Nie pomoże. Co ciekawe, nie masz takiego zachowania w pypy . Aby tego uniknąć, możesz użyćwhile True: line=sys.stdin.readline()
...
źródło
for line in sys.stdin
vs.for line in iter(sys.stdin.readline, "")
for line in sys.stdin
zapewnia opóźnioną odpowiedź)Jednym ze sposobów uzyskania niebuforowanych danych wyjściowych byłoby użycie
sys.stderr
zamiastsys.stdout
lub po prostu wywołanie wsys.stdout.flush()
celu jawnego wymuszenia zapisu.Możesz łatwo przekierować wszystko wydrukowane, wykonując:
Lub przekierować tylko dla określonej
print
instrukcji:Aby zresetować standardowe wyjście, wystarczy:
źródło