gpt4 book ai didi

python - 如果线程运行 webbrowser.open(),则无法使用 Ctrl-C 退出 Python 脚本

转载 作者:太空宇宙 更新时间:2023-11-03 11:44:06 25 4
gpt4 key购买 nike

我正在使用适用于 Python 的 Bottle 网络应用程序框架(pip install bottle),并希望运行一个只能从本地计算机访问的网络应用程序(它本质上是一个桌面应用程序,使用GUI 的浏览器)。要启动 bottle web 应用程序,我必须调用 bottle.run() 但只要脚本在运行,它就会一直阻塞。您可以按 Ctrl-C 停止它。

但是,我还希望此应用程序通过调用 webbrowser.open() 打开到本地主机的 Web 浏览器。问题是,我不能先调用 webbrowser.open() 因为网络应用程序不会运行,但如果我先调用 bottle.run()只要网络应用程序正在运行,我就不会返回,我无法继续调用 webbrowser.open()

我的解决方案是将对 webbrowser.open() 的调用放在一个线程中:

import bottle
import threading
import webbrowser
import time

class BrowserOpener(threading.Thread):
def run(self):
time.sleep(1) # waiting 1 sec is a hack, but it works
webbrowser.open('http://localhost:8042')
print('Browser opened')

@bottle.route('/')
def index():
return 'hello world!'

BrowserOpener().start()
bottle.run(host='localhost', port=8042)

问题是现在在终端中按 Ctrl-C 似乎不起作用,所以除了完全关闭终端之外我没有办法停止 Web 应用程序。我不确定这是为什么:'Browser opened' 被打印到屏幕上,所以我知道 webbrowser.open() 正在返回。

我在 Windows 7 上。

我已经尝试了来自 how to terminate a thread which calls the webbrowser in python 的解决方案设置 self._running = False 但这并没有改变任何东西。在线程之外也没有地方可以调用 join()

即使我摆脱了单独的线程并使用 os.system('python openbrowser.py') 运行等待一秒钟并打开网络浏览器的脚本,这仍然会阻止 Ctrl- C 从工作。

我还尝试使用 threading.Timer(1, webbrowser.open, ['http://localhost:8042']).start() 启动浏览器,但这仍然会阻止 Ctrl-C也从工作。

是否有我没有看到的解决方案?

最佳答案

关于此答案的两个直接警告:

  1. 可能有一种方法可以实现您想要的效果,它更接近您的原始设计。如果您不想偏离最初的想法那么多,也许另一个回答者可以提供更好的解决方案。
  2. 此解决方案尚未在 Windows 上进行测试,因此可能会遇到无法识别 Ctrl-C 信号的相同或类似问题。不幸的是,我手边没有带 Python 解释器的 Windows 机器,无法先试用。

把那个挡在一边:

您可能会发现将服务器放在一个单独的线程中然后通过一些简单的信号从主(非阻塞)线程控制它会更轻松。我在下面创建了一个玩具示例来演示我的意思。您可能更愿意将该类单独放入一个文件中,然后简单地将其导入并将该类的一个新实例实例化到您的其他脚本中。

import ctypes
import threading
import webbrowser
import bottle


class SimpleExampleApp():
def __init__(self):
self.app = bottle.Bottle()

#define all of the routes for your app inside the init method
@self.app.get('/')
def index():
return 'It works!'

@self.app.get('/other_route')
def alternative():
return 'This Works Too'

def run(self):
self.start_server_thread()
#depending upon how much configuration you are doing
#when you start the server you may need to add a brief
#delay before opening the browser to make sure that it
#is ready to receive the initial request
webbrowser.open('http://localhost:8042')

def start_server_thread(self):
self.server_thread = threading.Thread(
target = self.app.run,
kwargs = {'host': 'localhost', 'port': 8042}
)
self.server_thread.start()

def stop_server_thread(self):
stop = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(self.server_thread.get_ident()),
ctypes.py_object(KeyboardInterrupt)
)
#adding a print statement for debugging purposes since I
#do not know how well this will work on Windows platform
print('Return value of stop was {0}'.format(stop))
self.server_thread.join()


my_app = SimpleExampleApp()
my_app.run()

#when you're ready to stop the app, simply call
#my_app.stop_server_thread()

出于实际应用的目的,您可能需要对它进行相当大的修改,但它应该能帮助您入门。祝你好运!

关于python - 如果线程运行 webbrowser.open(),则无法使用 Ctrl-C 退出 Python 脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43399652/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com