You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bottle与Pywin32协同异常:Windows服务中导入Bottle报错

在Windows服务中导入Bottle框架触发AttributeError的解决方案

嘿,我完全懂你现在的困惑——作为Python新手,想把Bottle跑在Windows服务里,结果光是加个import bottle就炸了,这个问题其实是Windows服务的特性导致的,咱们来一步步解决它。

问题根源

Windows服务运行在没有控制台会话的环境里,默认情况下sys.stdout和sys.stderr是None,而Bottle在导入阶段(就是你写import bottle的那一刻)就会执行这段代码:

_stdout, _stderr = sys.stdout.write, sys.stderr.write

这时候sys.stdout是None,自然就会抛出AttributeError: 'NoneType' object has no attribute 'write'了。

解决方案

咱们有两种靠谱的方法来解决这个问题:

方法1:导入Bottle前重定向标准流

在导入Bottle之前,把sys.stdout和sys.stderr重定向到一个日志文件或者空设备(os.devnull),给Bottle提供一个有效的write对象:

import sys
import os

# 可选:重定向到日志文件,方便后续调试
log_file_path = os.path.join(os.path.dirname(__file__), "bottle_service_log.txt")
sys.stdout = open(log_file_path, "a", encoding="utf-8")
sys.stderr = open(log_file_path, "a", encoding="utf-8")

# 或者如果不需要日志,重定向到空设备
# sys.stdout = open(os.devnull, "w")
# sys.stderr = open(os.devnull, "w")

# 现在再导入Bottle就不会报错了
import bottle
import win32serviceutil
import win32service
import win32event
import servicemanager
import logging
import threading

class AppServerSvc(win32serviceutil.ServiceFramework):
    _svc_name_ = 'PestService'
    _svc_display_name_ = 'The Pest Service'
    _svc_description_ = "This service writes stuff to a file"
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
        self.main()
    def main(self):
        pass

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

方法2:延迟导入Bottle

不在模块顶层导入Bottle,而是等到服务启动后、已经处理好标准流的时机再导入,比如在SvcDoRun方法里:

import win32serviceutil
import win32service
import win32event
import servicemanager
import logging
import threading
import sys
import os

class AppServerSvc(win32serviceutil.ServiceFramework):
    _svc_name_ = 'PestService'
    _svc_display_name_ = 'The Pest Service'
    _svc_description_ = "This service writes stuff to a file"
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
    def SvcDoRun(self):
        # 先处理标准流
        log_file_path = os.path.join(os.path.dirname(__file__), "bottle_service_log.txt")
        sys.stdout = open(log_file_path, "a", encoding="utf-8")
        sys.stderr = open(log_file_path, "a", encoding="utf-8")
        
        # 延迟导入Bottle
        import bottle
        
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
        self.main()
    def main(self):
        pass

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

额外提示

如果你需要更专业的日志管理,建议使用Python的logging模块来替代直接重定向stdout/stderr,这样可以更好地控制日志级别、格式和存储方式,不过核心思路还是要保证Bottle导入时sys.stdout和sys.stderr不是None。

内容的提问来源于stack exchange,提问作者ramires.cabral

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:00:40