Gibt es eine Möglichkeit, einen sich drehenden Cursor in einem Terminal mit Python zu drucken?
70
Gibt es eine Möglichkeit, einen sich drehenden Cursor in einem Terminal mit Python zu drucken?
So etwas unter der Annahme, dass Ihr Terminal \ b handhabt
import sys
import time
def spinning_cursor():
while True:
for cursor in '|/-\\':
yield cursor
spinner = spinning_cursor()
for _ in range(50):
sys.stdout.write(next(spinner))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\b')
spinner = itertools.cycle(['-', '/', '|', '\\'])
anstatt eine Generatorfunktion (weniger ausführlich und mehr Wiederverwendung) wie hierspinner.next()
durch ersetzt wirdnext(spinner)
; Siehe stackoverflow.com/a/1073582/5025060 .Einfach zu verwendende API (dies führt den Spinner in einem separaten Thread aus):
import sys import time import threading class Spinner: busy = False delay = 0.1 @staticmethod def spinning_cursor(): while 1: for cursor in '|/-\\': yield cursor def __init__(self, delay=None): self.spinner_generator = self.spinning_cursor() if delay and float(delay): self.delay = delay def spinner_task(self): while self.busy: sys.stdout.write(next(self.spinner_generator)) sys.stdout.flush() time.sleep(self.delay) sys.stdout.write('\b') sys.stdout.flush() def __enter__(self): self.busy = True threading.Thread(target=self.spinner_task).start() def __exit__(self, exception, value, tb): self.busy = False time.sleep(self.delay) if exception is not None: return False
Verwenden Sie es jetzt in einem
with
Block an einer beliebigen Stelle im Code:with Spinner(): # ... some long-running operations # time.sleep(3)
quelle
float(delay)
wird erhöhen, wenn nicht schweben, sollte seinisinstance(delay, Number)
, mitNumber
vonnumbers
.Ein guter pythonischer Weg ist die Verwendung von itertools.cycle:
import itertools, sys spinner = itertools.cycle(['-', '/', '|', '\\']) while True: sys.stdout.write(next(spinner)) # write the next character sys.stdout.flush() # flush stdout buffer (actual character display) sys.stdout.write('\b') # erase the last written char
Möglicherweise möchten Sie auch Threading verwenden, um den Spinner während eines langen Funktionsaufrufs anzuzeigen, wie in http://www.interclasse.com/scripts/spin.php
quelle
next(spinner)
anstelle vonspinner.next()
spinner = itertools.cycle('-/|\\')
.Eine Lösung:
import sys import time print "processing...\\", syms = ['\\', '|', '/', '-'] bs = '\b' for _ in range(10): for sym in syms: sys.stdout.write("\b%s" % sym) sys.stdout.flush() time.sleep(.5)
Der Schlüssel besteht darin, das Rücktastezeichen '\ b' zu verwenden und stdout zu leeren.
quelle
Die verbesserte Version von @Victor Moyseenko als Originalversion hatte nur wenige Probleme
import sys import threading import itertools import time class Spinner: def __init__(self, message, delay=0.1): self.spinner = itertools.cycle(['-', '/', '|', '\\']) self.delay = delay self.busy = False self.spinner_visible = False sys.stdout.write(message) def write_next(self): with self._screen_lock: if not self.spinner_visible: sys.stdout.write(next(self.spinner)) self.spinner_visible = True sys.stdout.flush() def remove_spinner(self, cleanup=False): with self._screen_lock: if self.spinner_visible: sys.stdout.write('\b') self.spinner_visible = False if cleanup: sys.stdout.write(' ') # overwrite spinner with blank sys.stdout.write('\r') # move to next line sys.stdout.flush() def spinner_task(self): while self.busy: self.write_next() time.sleep(self.delay) self.remove_spinner() def __enter__(self): if sys.stdout.isatty(): self._screen_lock = threading.Lock() self.busy = True self.thread = threading.Thread(target=self.spinner_task) self.thread.start() def __exit__(self, exception, value, tb): if sys.stdout.isatty(): self.busy = False self.remove_spinner(cleanup=True) else: sys.stdout.write('\r')
Beispiel für die Verwendung der obigen Spinner-Klasse:
with Spinner("just waiting a bit.. "): time.sleep(3)
Code auf https://github.com/Tagar/stuff/blob/master/spinner.py hochgeladen
quelle
Schön, einfach und sauber ...
while True: for i in '|\\-/': print('\b' + i, end='')
quelle
Der Vollständigkeit halber möchte ich das großartige Paket Halo hinzufügen . Es bietet viele voreingestellte Spinner und Anpassungsoptionen auf höherer Ebene.
Auszug aus ihrer Readme
from halo import Halo spinner = Halo(text='Loading', spinner='dots') spinner.start() # Run time consuming work here # You can also change properties for spinner as and when you want spinner.stop()
Alternativ können Sie Halo mit Pythons with-Anweisung verwenden:
from halo import Halo with Halo(text='Loading', spinner='dots'): # Run time consuming work here
Schließlich können Sie Halo als Dekorateur verwenden:
from halo import Halo @Halo(text='Loading', spinner='dots') def long_running_function(): # Run time consuming work here pass long_running_function()
quelle
Sicher ist es möglich. Es ist nur eine Frage von Druck auf die Rück Zeichen (
\b
) zwischen den vier Zeichen, die den „Cursor“ schauen , wie es der Spinnen machen würden (-
,\
,|
,/
).quelle
Fluchmodul. Ich würde mir die Funktionen addstr () und addch () ansehen. Ich habe es aber nie benutzt.
quelle
Für erweiterte Konsolenmanipulationen können Sie unter Unix das Curses-Python-Modul und unter Windows WConio verwenden, das die gleiche Funktionalität wie die Curses-Bibliothek bietet.
quelle
Holen Sie sich das fantastische
progressbar
Modul - http://code.google.com/p/python-progressbar/ verwendenRotatingMarker
.quelle
Ich habe ein py-spin- Paket auf GitHub gefunden. Es hat viele schöne Spinnstile. Hier sind einige Beispiele zur Verwendung,
Spin1
ist der\-/
Stil:from __future__ import print_function import time from pyspin.spin import make_spin, Spin1 # Choose a spin style and the words when showing the spin. @make_spin(Spin1, "Downloading...") def download_video(): time.sleep(10) if __name__ == '__main__': print("I'm going to download a video, and it'll cost much time.") download_video() print("Done!") time.sleep(0.1)
Es ist auch möglich, das Spin-Handbuch manuell zu steuern:
from __future__ import print_function import sys import time from pyspin.spin import Spin1, Spinner # Choose a spin style. spin = Spinner(Spin1) # Spin it now. for i in range(50): print(u"\r{0}".format(spin.next()), end="") sys.stdout.flush() time.sleep(0.1)
Andere Stile im folgenden GIF.
quelle
#!/usr/bin/env python import sys chars = '|/-\\' for i in xrange(1,1000): for c in chars: sys.stdout.write(c) sys.stdout.write('\b') sys.stdout.flush()
CAVEATS: Nach meiner Erfahrung funktioniert dies nicht in allen Terminals. Eine robustere Möglichkeit, dies unter Unix / Linux zu tun, sei es komplizierter, ist die Verwendung des Curses- Moduls, das unter Windows nicht funktioniert. Sie möchten es wahrscheinlich etwas verlangsamen, wenn die eigentliche Verarbeitung im Hintergrund stattfindet.
quelle
Los geht's - einfach und klar.
import sys import time idx = 0 cursor = ['|','/','-','\\'] #frames of an animated cursor while True: sys.stdout.write(cursor[idx]) sys.stdout.write('\b') idx = idx + 1 if idx > 3: idx = 0 time.sleep(.1)
quelle
Grobe aber einfache Lösung:
import sys import time cursor = ['|','/','-','\\'] for count in range(0,1000): sys.stdout.write('\b{}'.format(cursor[count%4])) sys.stdout.flush() # replace time.sleep() with some logic time.sleep(.1)
Es gibt offensichtliche Einschränkungen, aber auch hier sind sie grob.
quelle
Ich schlage eine Lösung mit Dekorateuren vor
from itertools import cycle import functools import threading import time def spinner(message, spinner_symbols: list = None): spinner_symbols = spinner_symbols or list("|/-\\") spinner_symbols = cycle(spinner_symbols) global spinner_event spinner_event = True def start(): global spinner_event while spinner_event: symbol = next(spinner_symbols) print("\r{message} {symbol}".format(message=message, symbol=symbol), end="") time.sleep(0.3) def stop(): global spinner_event spinner_event = False print("\r", end="") def external(fct): @functools.wraps(fct) def wrapper(*args): spinner_thread = threading.Thread(target=start, daemon=True) spinner_thread.start() result = fct(*args) stop() spinner_thread.join() return result return wrapper return external
Einfache Bedienung
@spinner("Downloading") def f(): time.sleep(10)
quelle
Ich habe einen generischen Singleton erstellt, der von der gesamten Anwendung gemeinsam genutzt wird
from itertools import cycle import threading import time class Spinner: __default_spinner_symbols_list = ['|-----|', '|#----|', '|-#---|', '|--#--|', '|---#-|', '|----#|'] def __init__(self, spinner_symbols_list: [str] = None): spinner_symbols_list = spinner_symbols_list if spinner_symbols_list else Spinner.__default_spinner_symbols_list self.__screen_lock = threading.Event() self.__spinner = cycle(spinner_symbols_list) self.__stop_event = False self.__thread = None def get_spin(self): return self.__spinner def start(self, spinner_message: str): self.__stop_event = False time.sleep(0.3) def run_spinner(message): while not self.__stop_event: print("\r{message} {spinner}".format(message=message, spinner=next(self.__spinner)), end="") time.sleep(0.3) self.__screen_lock.set() self.__thread = threading.Thread(target=run_spinner, args=(spinner_message,), daemon=True) self.__thread.start() def stop(self): self.__stop_event = True if self.__screen_lock.is_set(): self.__screen_lock.wait() self.__screen_lock.clear() print("\r", end="") print("\r", end="") if __name__ == '__main__': import time # Testing spinner = Spinner() spinner.start("Downloading") # Make actions time.sleep(5) # Simulate a process # spinner.stop()
quelle
import sys def DrowWaitCursor(counter): if counter % 4 == 0: print("/",end = "") elif counter % 4 == 1: print("-",end = "") elif counter % 4 == 2: print("\\",end = "") elif counter % 4 == 3: print("|",end = "") sys.stdout.flush() sys.stdout.write('\b')
Dies kann auch eine andere Lösung sein, die eine Funktion mit einem Parameter verwendet.
quelle
Sie können schreiben
'\r\033[K'
, um die aktuelle Zeile zu löschen. Das folgende Beispiel wurde von @nos geändert.import sys import time def spinning_cursor(): while True: for cursor in '|/-\\': yield cursor spinner = spinning_cursor() for _ in range(1, 10): content = f'\r{next(spinner)} Downloading...' print(content, end="") time.sleep(0.1) print('\r\033[K', end="")
Für alle, die sich für nodejs interessieren, schreibe ich auch ein nodejs-Beispiel.
function* makeSpinner(start = 0, end = 100, step = 1) { let iterationCount = 0; while (true) { for (const char of '|/-\\') { yield char; } } return iterationCount; } async function sleep(seconds) { return new Promise((resolve) => { setTimeout(resolve, seconds * 1000); }); } (async () => { const spinner = makeSpinner(); for (let i = 0; i < 10; i++) { content = `\r${spinner.next().value} Downloading...`; process.stdout.write(content); await sleep(0.1); process.stdout.write('\r\033[K'); } })();
quelle
Ich habe gerade vor ungefähr einer Woche mit Python angefangen und diesen Beitrag gefunden. Ich habe ein bisschen von dem, was ich hier gefunden habe, mit Dingen kombiniert, die ich an anderer Stelle über Threads und Warteschlangen gelernt habe, um meiner Meinung nach eine viel bessere Implementierung zu ermöglichen. In meiner Lösung wird das Schreiben auf den Bildschirm von einem Thread behandelt, der eine Warteschlange auf Inhalt überprüft. Wenn diese Warteschlange Inhalt enthält, kann der sich drehende Cursorthread anhalten. Auf der Rückseite verwendet der sich drehende Cursor-Thread eine Warteschlange als Sperre, sodass der Druck-Thread nicht drucken kann, bis der vollständige Durchlauf des Spinner-Codes abgeschlossen ist. Dies verhindert Rennbedingungen und viele überschüssige Codes, die verwendet werden, um die Konsole sauber zu halten.
Siehe unten:
import threading, queue, itertools, sys, time # all required for my version of spinner import datetime #not required for spinning cursor solution, only my example console_queue = queue.Queue() # this queue should be initialized before functions screenlock = queue.Queue() # this queue too... def main(): threading.Thread(target=spinner).start() threading.Thread(target=consoleprint).start() while True: # instead of invoking print or stdout.write, we just add items to the console_queue # The next three lines are an example of my code in practice. time.sleep(.5) # wait half a second currenttime = "[" + datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") + "] " console_queue.put(currenttime) # The most important part. Substitute your print and stdout functions with this. def spinner(console_queue = console_queue, screenlock = screenlock): spinnerlist = itertools.cycle(['|', '/', '-', '\\']) while True: if console_queue.empty(): screenlock.put("locked") sys.stdout.write(next(spinnerlist)) sys.stdout.flush() sys.stdout.write('\b') sys.stdout.flush() screenlock.get() time.sleep(.1) def consoleprint(console_queue = console_queue, screenlock = screenlock): while True: if not console_queue.empty(): while screenlock.empty() == False: time.sleep(.1) sys.stdout.flush() print(console_queue.get()) sys.stdout.flush() if __name__ == "__main__": main()
Nachdem ich alles gesagt und geschrieben habe, was ich geschrieben habe, mache ich erst seit einer Woche Python-Sachen. Wenn es sauberere Möglichkeiten gibt oder ich einige Best Practices verpasst habe, würde ich gerne lernen. Vielen Dank.
quelle
import requests import time import sys weathercity = input("What city are you in? ") weather = requests.get('http://api.openweathermap.org/data/2.5/weather?q='+weathercity+'&appid=886705b4c1182eb1c69f28eb8c520e20') url = ('http://api.openweathermap.org/data/2.5/weather?q='+weathercity+'&appid=886705b4c1182eb1c69f28eb8c520e20') def spinning_cursor(): while True: for cursor in '|/-\\': yield cursor data = weather.json() temp = data['main']['temp'] description = data['weather'][0]['description'] weatherprint ="In {}, it is currently {}°C with {}." spinner = spinning_cursor() for _ in range(25): sys.stdout.write(next(spinner)) sys.stdout.flush() time.sleep(0.1) sys.stdout.write('\b') convert = int(temp - 273.15) print(weatherprint.format(weathercity, convert, description))
quelle
def spinning_cursor()...
undsys.stdout.write(next(spinner)) ....
] des Codes in der 9 Jahre alten Antwort von nos . Bitte kopieren Sie nicht (Teile) der Antworten anderer Personen und geben Sie sie als Ihre eigenen weiter. Und wenn Sie ältere Fragen beantworten, stellen Sie bitte sicher, dass Sie entweder eine andere Lösung oder zumindest eine wesentlich bessere Erklärung als die aktuellen Antworten angeben.