【发布时间】:2020-05-10 00:05:00
【问题描述】:
我正在开发一个基于 VLC 和 Curses 的终端界面音频播放器。
最近有人建议我在 SE Code Review post 上使用异常来退出程序,而不是使用 global 布尔值作为信号。
但是,当我将代码转换为使用 SystemExit 异常时,它会停止完全退出,而是挂起直到终端窗口关闭。我认为这个问题与 Pynput 的侦听器以及我如何处理它创建的线程有关,但我不确定。
使用布尔值:
import sys, os
from pynput import keyboard
from functools import partial
import cfg
from view import View
from player import Player
exit_signal: bool = False
def on_press(key: keyboard.KeyCode, view: View, player: Player):
"""Handle input"""
global exit_signal
key = str(key).strip('\'')
if str(key) == 'p':
view.notify('Playing...')
player.play()
elif key == 'a':
view.notify('Paused')
player.pause()
elif key == 'n':
view.notify('Skipping Forward...')
player.skip_forward()
elif key == 'l':
view.notify('Skipping Back...')
player.skip_back()
elif key == 'q':
view.notify('Exiting...')
exit_signal = True
del player
del view
return
view.update_ui(player.get_metadata())
def tick(view: View, player:Player):
"""For functions run periodically"""
metadata = player.get_metadata()
view.update_ui(metadata)
view = View()
player = Player()
view.notify("Ready!")
with keyboard.Listener(on_press=partial(on_press, view=view, player=player)) as listener:
while exit_signal == False:
tick(view, player)
listener.join() # merge to one thread
os.system('reset') # clean up the console
使用 SystemExit:
from os import system
from pynput import keyboard
from functools import partial
import cfg
from view import View
from player import Player
def on_press(key: keyboard.KeyCode, view: View, player: Player):
"""Handle user input"""
key = str(key).strip('\'')
if str(key) == 'p':
view.notify('Playing...')
player.play()
elif key == 'a':
view.notify('Paused')
player.pause()
elif key == 'n':
view.notify('Skipping Forward...')
player.skip_forward()
elif key == 'l':
view.notify('Skipping Back...')
player.skip_back()
elif key == 'q':
view.notify('Exiting...')
del player
del view
raise SystemExit
view.update_ui(player.get_metadata())
def tick(view: View, player: Player):
"""For functions run periodically"""
metadata = player.get_metadata()
view.update_ui(metadata)
view = View()
player = Player()
view.notify("Ready!")
listener = keyboard.Listener(
on_press=partial(on_press, view=view, player=player))
listener.start()
try:
while True:
tick(view, player)
except SystemExit:
listener.join() # merge back to one thread
os.system('cls' if os.name == 'nt' else 'clear')
我希望两个 sn-ps 的行为相同并在按下“q”时退出,但只有布尔方法正常工作。
此代码也在github 上。感谢您的宝贵时间。
【问题讨论】:
-
根据文档here,它声明:“从任何地方调用
pynput.mouse.Listener.stop,raise StopException或从回调中返回False以停止侦听器。” -
这可能是您的程序在
raise StopException上的listener.start()处退出,但随后它卡在while True: tick(view, player)行内——并且函数tick永远不会引发SystemExit,所以你的程序永远不会到达except语句,或者它的结尾。 -
@FelipeFaria 谢谢,您的观察使我找到了我在下面发布的另一个解决方案。
标签: python multithreading exception pynput