Print statements not working when serve_forever() is called?

早过忘川 提交于 2020-01-01 06:57:05

问题


I have the following small python script to run a local server for testing some 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()

When I run this in the terminal, it blocks the print statements: nothing is printed. But the server works and I can go to localhost:8000 in the browser and access my html files. If, however, I comment out the last line, the call to serve_forever(), it works, printing both 'opened' and 'Listening at https:127.0.0.1:8000/ . . .'. Except of course it doesn't actually work, since now the server isn't being run.

I find this very confusing. The previous lines are executed before the last line. Why would the last line cause the previous lines to not work?

Python3 on Windows7 if anyone was going to ask, but I doubt that's relevant.


回答1:


That maybe related with the "infamous" need to flush in order for your prints to work!

Related reading material:

  • Theoretical knowledge on the subject
  • How to flush output of Python print?, python `print` does not work in loop, as suggested by @Kerorin:


Because you are using Python 3 and since version 3.3 you don't have to follow the solutions given in the above great answers.
The print build-in type has an option flush which by default is False. Do:
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:


There several solutions for this phenomena:

Disable output buffering

Reopen stdout file descriptor with write mode, and 0 as the buffer size (unbuffered). I suggest to write this line as the first line in your code, and this way, all your code will remain the same except the stdout buffer:

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

Run python with unbuffered binary stdout and stderr

Force the binary layer of the stdout and stderr streams (which is available as their buffer attribute) to be unbuffered. The text I/O layer will still be line-buffered if writing to the console, or block-buffered if redirected to a non-interactive file.

So just run your script like this:

python -u <your_pyScript>

Or by setting the environment variable PYTHONUNBUFFERED

Set flush keyword argument to true

Since Python 3.3, you can force the normal print() function to flush without the need to use sys.stdout.flush() just set the "flush" keyword argument to true:

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

Changing the default in one module to flush=True

You can change the default for the print function by using functools.partial on the global scope of a module:

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

We can see it works just as expected:

>>> print('foo')
foo



回答3:


import logging
logging.info('Listening at https://127.0.0.1:8000/ . . .')

Hi, please, consider using logging instead of printing, you do not want bother with all the shortcomings of the print statement. Print is for beginners, may be for interactive mode. All the professional server-side coders rely on logging.

Check In python, why use logging instead of print? for the full list of logging goodness.



来源:https://stackoverflow.com/questions/43197518/print-statements-not-working-when-serve-forever-is-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!