【问题标题】:Print statements not working when serve_forever() is called?调用 serve_forever() 时打印语句不起作用?
【发布时间】:2017-08-29 01:55:50
【问题描述】:

我有以下小的 python 脚本来运行本地服务器来测试一些 html:

print('opened')

from http.server import HTTPServer, SimpleHTTPRequestHandler

server_address = ('', 8000)
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)

print("Listening at https://127.0.0.1:8000/ . . .")
httpd.serve_forever()

当我在终端中运行它时,它会阻止 print 语句:没有打印任何内容。但是服务器工作正常,我可以在浏览器中转到localhost:8000 并访问我的html 文件。但是,如果我注释掉最后一行,即对serve_forever() 的调用,它可以工作,同时打印 'opened' 和 'Listening at https:127.0.0.1:8000/ 。 . .'.当然除了它实际上没有工作,因为现在服务器没有运行。

我觉得这很令人困惑。前几行在最后一行之前执行。为什么最后一行会导致前面的行不起作用?

如果有人要问,Windows7 上的 Python3,但我怀疑这是否相关。

【问题讨论】:

  • 如果您在最后一个print 之前调用sys.stdout.flush(),会打印任何内容吗?
  • 因为我尝试执行相同的操作,并且在服务器运行的同时收到了两条消息。能否请您提及您的平台和 python3 版本?
  • 您的打印没有发生的原因是,您的操作系统提供的库正在缓冲输出。因为我使用的是 Linux,所以它不适合我。 sys.stdout.flush 强制它显示缓冲到该点的任何内容。
  • 仅供参考,与 OP 相同的代码在 Mac OS X 上对我来说效果很好。
  • 我想你会喜欢这些帖子 stackoverflow.com/questions/230751/…stackoverflow.com/questions/25368786/… 不冲洗也不会很好用。

标签: python python-3.x simplehttpserver


【解决方案1】:

这可能与“臭名昭著”的需要冲洗有关,以便您的打印工作!

相关阅读材料:


因为您使用的是 Python 3,并且从 3.3 版开始,您不必遵循上述出色答案中给出的解决方案。
print build-in type 有一个选项flush,默认为False。做:
print('opened', flush=True)

from http.server import HTTPServer, SimpleHTTPRequestHandler

server_address = ('', 8000)
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)

print('Listening at https://127.0.0.1:8000/ . . .', flush=True)
httpd.serve_forever()

PS:This is a confirmed solution on a similar issue

【讨论】:

    【解决方案2】:

    这种现象有几种解决方案:

    禁用输出缓冲

    以写入模式重新打开 stdout 文件描述符,并将 0 作为缓冲区大小(未缓冲)。我建议将此行写为代码的第一行,这样,除了stdout 缓冲区之外,您的所有代码都将保持不变:

    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
    

    使用无缓冲的二进制标准输出和标准错误运行 python

    强制 stdout 和 stderr 流的二进制层(可作为它们的缓冲区属性使用)无缓冲。如果写入控制台,文本 I/O 层仍将是行缓冲,如果重定向到非交互式文件,则仍将是块缓冲。

    所以只需像这样运行您的脚本:

    python -u <your_pyScript>
    

    或者通过设置环境变量PYTHONUNBUFFERED

    flush关键字参数设置为true

    从 Python 3.3 开始,您可以强制普通的 print() 函数刷新,而无需使用 sys.stdout.flush(),只需将“flush”关键字参数设置为 true:

    print("...", flush=True)
    

    将一个模块中的默认值更改为flush=True

    您可以在模块的全局范围内使用functools.partial 更改打印功能的默认值:

    import functools
    print = functools.partial(print, flush=True)
    

    我们可以看到它按预期工作:

    >>> print('foo')
    foo
    

    【讨论】:

    • 您的第 2、第 3 和第 4 个解决方案当然都可以完美运行,但第一个给我一个错误:File "C:\Users\Aerovistae\AppData\Local\Programs\Python\Python36-32\lib\os.py", line 1015, in fdopen return io.open(fd, *args, **kwargs) ValueError: can't have unbuffered text I/O Exception ignored in: &lt;_io.TextIOWrapper name='&lt;stdout&gt;' mode='w' encoding='cp1252'&gt; OSError: [Errno 9] Bad file descriptor
    【解决方案3】:
    import logging
    logging.info('Listening at https://127.0.0.1:8000/ . . .')
    

    您好,请考虑使用日志记录而不是打印,您不想为打印语句的所有缺点而烦恼。打印适合初学者,可能适合交互模式。所有专业的服务器端编码器都依赖于日志记录。

    检查 In python, why use logging instead of print? 获取完整的日志记录列表。

    【讨论】:

    • 实际上并没有回答这个问题,这是关于理解为什么会发生这种情况,但无论如何确实提供了一个非常有用的相关建议!赞成。我之前没有遇到过日志记录模块。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-19
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多