Dynamiczne drukowanie terminali w Pythonie

Niektóre aplikacje jak hellanzb mają sposób drukowania do terminala z wyglądem dynamicznie odświeżających danych, jak top ().

Jaka jest najlepsza metoda w Pythonie? Czytałem o logowaniu i przekleństwach, ale nie wiem, czego użyć. Tworzę reimplementację top. Jeśli macie jakieś inne sugestie, również jestem na nie otwarty.

Author: Recursion , 2010-01-23

7 answers

Najprostszym sposobem, jeśli potrzebujesz tylko zaktualizować pojedynczą linię (na przykład tworząc pasek postępu), jest użycie '\r' (powrót karetki) i sys.stdout:

import sys
import time

for i in range(10):
    sys.stdout.write("\r{0}>".format("="*i))
    sys.stdout.flush()
    time.sleep(0.5)

Jeśli potrzebujesz odpowiedniego interfejsu konsoli, który obsługuje Przesuwanie wskaźnika itp., użyj curses Moduł z biblioteki standardowej:

import time
import curses

def pbar(window):
    for i in range(10):
        window.addstr(10, 10, "[" + ("=" * i) + ">" + (" " * (10 - i )) + "]")
        window.refresh()
        time.sleep(0.5)

curses.wrapper(pbar)

Jest wysoce wskazane, aby użyć curses.wrapper funkcja aby wywołać główną funkcję, zajmie się czyszczeniem terminala w przypadku błędu, więc nie będzie w stan później bezużyteczny.

Jeśli utworzysz bardziej złożony interfejs użytkownika, możesz utworzyć wiele okien dla różnych części ekranu, pól wprowadzania tekstu i obsługi myszy.

 39
Author: Torsten Marek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-23 11:31:21

Jak już większość odpowiedzi stwierdziła, na Linuksie naprawdę niewiele jest opcji poza używaniem ncurses. Ale co, jeśli nie jesteś na Linuksie lub chcesz czegoś bardziej wysokiego poziomu do tworzenia interfejsu terminala?

Osobiście uważam, że brak nowoczesnego, wieloplatformowego terminala API w Pythonie jest frustrujący, więc napisałem asciimatics , aby rozwiązać ten problem. Nie tylko daje proste wieloplatformowe API , ale także zapewnia wiele abstrakcji wyższego poziomu dla UI widżety i animacje , które można łatwo wykorzystać do stworzenia interfejsu przypominającego górę.

 12
Author: Peter Brittain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-08 22:12:25

Brzmi jak praca dla curses. Jest to najczęściej używana biblioteka do układania i zarządzania ekranem w trybie tekstowym. Python ma bardzo dobre wsparcie dla curses, w tym wsparcie dla paneli:

 2
Author: gavinb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-23 06:51:57

Zhakowałem ten skrypt używając curses. To naprawdę rozwiązanie ad-hoc zrobiłem dla Zabawy. Nie obsługuje przewijania, ale myślę, że jest to dobry punkt wyjścia, jeśli chcesz zbudować monitor aktualizacji na żywo z wieloma wierszami na terminalu.

Https://gist.github.com/tpandit/b2bc4f434ee7f5fd890e095e79283aec

 1
Author: tejas pandit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-08 19:31:14

Kiedy robię to w skryptach powłoki na Uniksie, zwykle używam tylko programu clear. Możesz użyć modułu podprocesu Pythona, aby go wykonać. Przynajmniej szybko dostaniesz to, czego szukasz.

 0
Author: Omnifarious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-23 06:47:33
[ignacio@localhost ~]$ ldd /usr/bin/top | grep curses
        libncursesw.so.5 => /lib64/libncursesw.so.5 (0x0000003ae1400000)

curses tak.

 0
Author: Ignacio Vazquez-Abrams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-23 06:48:40

Wysyłanie wyjścia do terminala za pomocą polecenia print() może być wykonane bez przewijania, jeśli użyjesz atrybutu "end".

Wartością domyślną jest end= '\N', czyli nowa linia.

Aby wyłączyć przewijanie i nadpisać całą poprzednią linię, możesz użyć ucieczki powrotu, która jest '\r'.

Jeśli chcesz przepisać tylko cztery ostatnie znaki, możesz użyć kilku spacji.

print(value, "_of_", total, end='\r')

Uwaga Działa to dla standardowego terminala systemowego. Terminal emulator w niektórych narzędziach, takich jak IDLE ma błąd i '\R' nie działa poprawnie, wyjście jest po prostu połączone z jakimś niedrukowalnym znakiem pomiędzy.

Informacje dodatkowe dla print () W powyższym przykładzie spacje po każdej stronie "of "mają na celu zapewnienie białej przestrzeni między moimi wartościami a słowem"of". Jednak domyślnym separatorem print () jest "" (spacja), więc kończymy z białą spacją między wartością a podkreśleniem "_of_".

>> print (value, "_of_", total, end='\r')
8 _of_ 17

Atrybut sepparator, sep, może być używany do ustawiania znaków pomiędzy drukowanymi elementami. W moim przykładzie zmienię go na null string ( " ), aby moje wyjście odpowiadało moim potrzebom.

>> print (value, "_of_", total, sep='', end='\r')
8_of_17
 0
Author: GT Electronics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-29 17:33:14