如何通过PYTHONSTARTUP配置多行Python交互式提示符sys.ps1以避免重复输出问题
如何通过PYTHONSTARTUP配置多行Python交互式提示符sys.ps1以避免重复输出问题
我完全理解你遇到的麻烦——想在Python交互提示符里搞个多行样式,第一行显示路径和时间,第二行是输入提示符,但不管是直接用多行字符串还是带__repr__的类,要么输入时第一行被反复覆盖,要么每打一个字符就重复刷第一行,简直头疼!
咱们先扒一扒为啥之前的方法不管用:
- 直接设置多行
sys.ps1:Windows CMD里的Python交互环境没有像Unix那样的readline支持,每次输入字符时终端会重新渲染整个提示符,导致第一行被反复打印覆盖。 - 带
__repr__的类:你的__repr__里用了print,而Python在输入过程中(尤其是CMD环境)会频繁调用sys.ps1的生成逻辑,每输入一个字符就触发一次__repr__,自然会反复打印第一行。
可行的解决方案
核心思路是:只在命令执行完成后才打印第一行的路径和时间,输入过程中绝不重复打印。我们可以用一个标志位来区分「新命令开始」和「正在输入」的状态,再配合重写Python的displayhook和excepthook来控制这个标志位。
把你原来的代码改成下面这样:
import sys import datetime import os import ctypes from BlurWindow.blurWindow import GlobalBlur as gb__ # 保留你原有的窗口模糊设置 gb__(ctypes.windll.user32.GetForegroundWindow(), '#000000CC', True, True) # ANSI颜色控制码(保留你的定义) c__ = "\033[38;5;" e__ = "\033[m" # 二级提示符(保留你的设置) sys.ps2 = f"{c__}125m... {e__}" # 判断是否为管理员(保留你的逻辑) is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0 prompt_char = "#" if is_admin else ">" # 标志位:标记是否是新命令的起始状态 new_command = True class DynamicPS1: def __repr__(self): global new_command if new_command: # 仅在新命令开始时打印路径和时间 current_time = datetime.datetime.now().strftime("%H:%M:%S") current_path = os.path.abspath(os.getcwd()) # 用sys.stdout.write+flush确保输出立即生效,避免缓冲问题 sys.stdout.write(f"{c__}208m{current_path} {c__}106m{current_time}{e__}\n") sys.stdout.flush() # 切换状态:输入过程中不再打印第一行 new_command = False # 返回第二行的输入提示符 return f"{c__}125mPY{prompt_char} {e__}" sys.ps1 = DynamicPS1() # 重写displayhook:命令执行完成后,重置标志位为新命令状态 original_displayhook = sys.displayhook def custom_displayhook(value): global new_command original_displayhook(value) new_command = True sys.displayhook = custom_displayhook # 重写excepthook:处理Ctrl+C或异常情况,确保标志位正确重置 original_excepthook = sys.excepthook def custom_excepthook(type, value, traceback): global new_command original_excepthook(type, value, traceback) new_command = True sys.excepthook = custom_excepthook
代码工作原理
- 标志位控制:
new_command变量用来判断是否需要打印第一行信息,只有在上一条命令执行完成(或刚进入交互环境)时才会打印。 - displayhook重写:Python执行完每条命令后都会调用
displayhook,我们在这里把标志位重置为True,为下一条命令的提示符做准备。 - excepthook重写:处理用户按
Ctrl+C或命令抛出异常的情况,确保标志位被正确重置,不会影响下一次提示符的显示。 - 直接写标准输出:用
sys.stdout.write代替print,并手动调用flush,避免输出缓冲导致的显示延迟或错位。
这样修改后,你就能得到想要的效果:
- 执行完命令后,自动打印最新的路径和时间,然后显示输入提示符
- 输入字符时,不会重复打印第一行信息,光标正常在提示符后移动
- 按
Ctrl+C或命令报错后,下一次提示符依然会正确显示路径和时间
备注:内容来源于stack exchange,提问作者AnikeiPS
相关产品推荐
相关产品推荐

