如何创建旋转命令行光标?

Nat*_*han 61 python progress command-line-interface

有没有办法使用Python在终端中打印旋转光标?

nos*_*nos 68

这样的事情,假设您的终端处理\ b

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')
Run Code Online (Sandbox Code Playgroud)

  • 您可能希望使用`spinner = itertools.cycle([' - ','/','|','\\'])`而不是创建生成器函数(更简洁,更多重用),如此处所示[here] (http://stackoverflow.com/a/22616059/1300775) (12认同)
  • 请注意,在Python 3中,`spinner.next()`被`next(spinner)`替换; 见http://stackoverflow.com/a/1073582/5025060. (7认同)

小智 41

易于使用的API(这将在单独的线程中运行运行微调器):

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
Run Code Online (Sandbox Code Playgroud)

代码中的任何位置:

with Spinner():
  # ... some long-running operations
  # time.sleep(3) 
Run Code Online (Sandbox Code Playgroud)

  • 这非常好,直到您在代码中遇到未处理的错误.然后你不能强迫它停止. (6认同)

Dam*_*ien 34

一个不错的pythonic方法是使用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
Run Code Online (Sandbox Code Playgroud)

此外,您可能希望在长函数调用期间使用线程来显示微调器,如http://www.interclasse.com/scripts/spin.php

  • 根据另一个答案中CODE-REaD的注释,在python 3中,使用`next(spinner)`代替`spinner.next()`。 (4认同)
  • 简而言之,简单地使用`spinner = itertools.cycle('-/ | \\')`。 (2认同)

Nat*_*han 10

一个办法:

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)
Run Code Online (Sandbox Code Playgroud)

关键是使用退格符'\ b'和刷新标准输出.


Han*_*ans 8

例子

为了完整起见,我想添加很棒的包halo。它提供了许多预设微调器和更高级别的自定义选项。

摘自他们的自述文件

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()
Run Code Online (Sandbox Code Playgroud)

或者,您可以在 Python 的 with 语句中使用 halo:

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()
Run Code Online (Sandbox Code Playgroud)

最后,您可以使用 halo 作为装饰器:

from halo import Halo

with Halo(text='Loading', spinner='dots'):
    # Run time consuming work here
Run Code Online (Sandbox Code Playgroud)


Tag*_*gar 6

来自@Victor Moyseenko 的改进版本,因为原始版本几乎没有问题

  1. 旋转完成后离开旋转器的角色
  2. 有时也会导致删除以下输出的第一个字符
  3. 通过在输出上放置 threading.Lock() 来避免罕见的竞争条件
  4. 当没有 tty 可用时回退到更简单的输出(不旋转)
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')

Run Code Online (Sandbox Code Playgroud)

上面 Spinner 类的使用示例:


with Spinner("just waiting a bit.. "):

        time.sleep(3)

Run Code Online (Sandbox Code Playgroud)

上传代码到https://github.com/Tagar/stuff/blob/master/spinner.py