将 stdout 重定向到 Python 中的文件?

发布于 2024-10-11 10:17:28 字数 425 浏览 5 评论 0原文

如何将 stdout 重定向到 Python 中的任意文件?

当长时间运行的 Python 脚本(例如 Web 应用程序)从 ssh 会话中启动并处于后台,并且 ssh 会话关闭时,应用程序将引发 IOError 并在尝试写入 stdout 时失败。我需要找到一种方法使应用程序和模块输出到文件而不是标准输出,以防止由于 IOError 导致失败。目前,我使用 nohup 将输出重定向到文件,这样就完成了工作,但出于好奇,我想知道是否有一种方法可以在不使用 nohup 的情况下完成此任务。

我已经尝试过 sys.stdout = open('somefile', 'w') ,但这似乎并不能阻止某些外部模块仍然输出到终端(或者可能是 sys.stdout )。 stdout = ... 行根本没有触发)。我知道它应该可以从我测试过的更简单的脚本中运行,但我还没有时间在 Web 应用程序上进行测试。

How do I redirect stdout to an arbitrary file in Python?

When a long-running Python script (e.g, web application) is started from within the ssh session and backgounded, and the ssh session is closed, the application will raise IOError and fail the moment it tries to write to stdout. I needed to find a way to make the application and modules output to a file rather than stdout to prevent failure due to IOError. Currently, I employ nohup to redirect output to a file, and that gets the job done, but I was wondering if there was a way to do it without using nohup, out of curiosity.

I have already tried sys.stdout = open('somefile', 'w'), but this does not seem to prevent some external modules from still outputting to terminal (or maybe the sys.stdout = ... line did not fire at all). I know it should work from simpler scripts I've tested on, but I also didn't have time yet to test on a web application yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

梦在深巷 2024-10-18 10:17:28

如果您想在 Python 脚本中进行重定向,将 sys.stdout 设置为文件对象即可:

# for python3
import sys
with open('file', 'w') as sys.stdout:
    print('test')

更常见的方法是在执行时使用 shell 重定向(在 Windows 和 Linux 上也是如此) :

$ python3 foo.py > file

If you want to do the redirection within the Python script, setting sys.stdout to a file object does the trick:

# for python3
import sys
with open('file', 'w') as sys.stdout:
    print('test')

A far more common method is to use shell redirection when executing (same on Windows and Linux):

$ python3 foo.py > file
两个我 2024-10-18 10:17:28

contextlib.redirect_stdout() 函数 在 Python 3.4+ 中:

from contextlib import redirect_stdout

with open('help.txt', 'w') as f:
    with redirect_stdout(f):
        print('it now prints to `help.text`')

它类似于:

import sys
from contextlib import contextmanager

@contextmanager
def redirect_stdout(new_target):
    old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
    try:
        yield new_target # run some code with the replaced stdout
    finally:
        sys.stdout = old_target # restore to the previous value

可以在早期的 Python 版本上使用。后一个版本不可可重用。如果需要的话可以制作一个。

它不会在文件描述符级别重定向标准输出,例如:

import os
from contextlib import redirect_stdout

stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, redirect_stdout(f):
    print('redirected to a file')
    os.write(stdout_fd, b'not redirected')
    os.system('echo this also is not redirected')

b'not redirected''echo this is not redirected' 不会重定向到 输出.txt 文件。

要在文件描述符级别重定向,可以使用 os.dup2() :

import os
import sys
from contextlib import contextmanager

def fileno(file_or_fd):
    fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
    if not isinstance(fd, int):
        raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
    return fd

@contextmanager
def stdout_redirected(to=os.devnull, stdout=None):
    if stdout is None:
       stdout = sys.stdout

    stdout_fd = fileno(stdout)
    # copy stdout_fd before it is overwritten
    #NOTE: `copied` is inheritable on Windows when duplicating a standard stream
    with os.fdopen(os.dup(stdout_fd), 'wb') as copied: 
        stdout.flush()  # flush library buffers that dup2 knows nothing about
        try:
            os.dup2(fileno(to), stdout_fd)  # $ exec >&to
        except ValueError:  # filename
            with open(to, 'wb') as to_file:
                os.dup2(to_file.fileno(), stdout_fd)  # $ exec > to
        try:
            yield stdout # allow code to be run with the redirected stdout
        finally:
            # restore stdout to its previous value
            #NOTE: dup2 makes stdout_fd inheritable unconditionally
            stdout.flush()
            os.dup2(copied.fileno(), stdout_fd)  # $ exec >&copied

如果使用 stdout_redirected() 而不是 redirect_stdout(),则现在可以使用相同的示例:

import os
import sys

stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, stdout_redirected(f):
    print('redirected to a file')
    os.write(stdout_fd, b'it is redirected now\n')
    os.system('echo this is also redirected')
print('this is goes back to stdout')

只要 stdout_redirected() 上下文管理器处于活动状态,以前在 stdout 上打印的输出现在就会转到 output.txt

注意:stdout.flush() 不会刷新
Python 3 上的 C stdio 缓冲区,其中 I/O 直接在 read()/write() 系统调用上实现。要刷新所有打开的 C stdio 输出流,如果某些 C 扩展使用基于 stdio 的 I/O,则可以显式调用 libc.fflush(None)

try:
    import ctypes
    from ctypes.util import find_library
except ImportError:
    libc = None
else:
    try:
        libc = ctypes.cdll.msvcrt # Windows
    except OSError:
        libc = ctypes.cdll.LoadLibrary(find_library('c'))

def flush(stream):
    try:
        libc.fflush(None)
        stream.flush()
    except (AttributeError, ValueError, IOError):
        pass # unsupported

您可以使用 stdout 参数重定向其他流,而不仅仅是 sys.stdout 例如,合并 sys.stderrsys.stdout

def merged_stderr_stdout():  # $ exec 2>&1
    return stdout_redirected(to=sys.stdout, stdout=sys.stderr)

示例:

from __future__ import print_function
import sys

with merged_stderr_stdout():
     print('this is printed on stdout')
     print('this is also printed on stdout', file=sys.stderr)

注意: stdout_redirected() 混合缓冲 I/O(通常为 sys.stdout)和非缓冲 I/O(直接对文件描述符进行操作)。请注意,可能存在缓冲问题

要回答,您的编辑:您可以使用 python-daemon 守护程序化您的脚本并使用 logging 模块(如 @erikb85 建议)而不是 print 语句,并且仅重定向您现在使用 nohup 运行的长时间运行的 Python 脚本的标准输出。

There is contextlib.redirect_stdout() function in Python 3.4+:

from contextlib import redirect_stdout

with open('help.txt', 'w') as f:
    with redirect_stdout(f):
        print('it now prints to `help.text`')

It is similar to:

import sys
from contextlib import contextmanager

@contextmanager
def redirect_stdout(new_target):
    old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
    try:
        yield new_target # run some code with the replaced stdout
    finally:
        sys.stdout = old_target # restore to the previous value

that can be used on earlier Python versions. The latter version is not reusable. It can be made one if desired.

It doesn't redirect the stdout at the file descriptors level e.g.:

import os
from contextlib import redirect_stdout

stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, redirect_stdout(f):
    print('redirected to a file')
    os.write(stdout_fd, b'not redirected')
    os.system('echo this also is not redirected')

b'not redirected' and 'echo this also is not redirected' are not redirected to the output.txt file.

To redirect at the file descriptor level, os.dup2() could be used:

import os
import sys
from contextlib import contextmanager

def fileno(file_or_fd):
    fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
    if not isinstance(fd, int):
        raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
    return fd

@contextmanager
def stdout_redirected(to=os.devnull, stdout=None):
    if stdout is None:
       stdout = sys.stdout

    stdout_fd = fileno(stdout)
    # copy stdout_fd before it is overwritten
    #NOTE: `copied` is inheritable on Windows when duplicating a standard stream
    with os.fdopen(os.dup(stdout_fd), 'wb') as copied: 
        stdout.flush()  # flush library buffers that dup2 knows nothing about
        try:
            os.dup2(fileno(to), stdout_fd)  # $ exec >&to
        except ValueError:  # filename
            with open(to, 'wb') as to_file:
                os.dup2(to_file.fileno(), stdout_fd)  # $ exec > to
        try:
            yield stdout # allow code to be run with the redirected stdout
        finally:
            # restore stdout to its previous value
            #NOTE: dup2 makes stdout_fd inheritable unconditionally
            stdout.flush()
            os.dup2(copied.fileno(), stdout_fd)  # $ exec >&copied

The same example works now if stdout_redirected() is used instead of redirect_stdout():

import os
import sys

stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, stdout_redirected(f):
    print('redirected to a file')
    os.write(stdout_fd, b'it is redirected now\n')
    os.system('echo this is also redirected')
print('this is goes back to stdout')

The output that previously was printed on stdout now goes to output.txt as long as stdout_redirected() context manager is active.

Note: stdout.flush() does not flush
C stdio buffers on Python 3 where I/O is implemented directly on read()/write() system calls. To flush all open C stdio output streams, you could call libc.fflush(None) explicitly if some C extension uses stdio-based I/O:

try:
    import ctypes
    from ctypes.util import find_library
except ImportError:
    libc = None
else:
    try:
        libc = ctypes.cdll.msvcrt # Windows
    except OSError:
        libc = ctypes.cdll.LoadLibrary(find_library('c'))

def flush(stream):
    try:
        libc.fflush(None)
        stream.flush()
    except (AttributeError, ValueError, IOError):
        pass # unsupported

You could use stdout parameter to redirect other streams, not only sys.stdout e.g., to merge sys.stderr and sys.stdout:

def merged_stderr_stdout():  # $ exec 2>&1
    return stdout_redirected(to=sys.stdout, stdout=sys.stderr)

Example:

from __future__ import print_function
import sys

with merged_stderr_stdout():
     print('this is printed on stdout')
     print('this is also printed on stdout', file=sys.stderr)

Note: stdout_redirected() mixes buffered I/O (sys.stdout usually) and unbuffered I/O (operations on file descriptors directly). Beware, there could be buffering issues.

To answer, your edit: you could use python-daemon to daemonize your script and use logging module (as @erikb85 suggested) instead of print statements and merely redirecting stdout for your long-running Python script that you run using nohup now.

愚人国度 2024-10-18 10:17:28

你可以尝试这个更好

import sys

class Logger(object):
    def __init__(self, filename="Default.log"):
        self.terminal = sys.stdout
        self.log = open(filename, "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

sys.stdout = Logger("yourlogfilename.txt")
print "Hello world !" # this is should be saved in yourlogfilename.txt

you can try this too much better

import sys

class Logger(object):
    def __init__(self, filename="Default.log"):
        self.terminal = sys.stdout
        self.log = open(filename, "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

sys.stdout = Logger("yourlogfilename.txt")
print "Hello world !" # this is should be saved in yourlogfilename.txt
小女人ら 2024-10-18 10:17:28

其他答案没有涵盖您希望分叉进程共享新标准输出的情况。

为此:

from os import open, close, dup, O_WRONLY

old = dup(1)
close(1)
open("file", O_WRONLY) # should open on 1

..... do stuff and then restore

close(1)
dup(old) # should dup to 1
close(old) # get rid of left overs

The other answers didn't cover the case where you want forked processes to share your new stdout.

To do that:

from os import open, close, dup, O_WRONLY

old = dup(1)
close(1)
open("file", O_WRONLY) # should open on 1

..... do stuff and then restore

close(1)
dup(old) # should dup to 1
close(old) # get rid of left overs
黯然 2024-10-18 10:17:28

引自 PEP 343 -- The "with" 语句 (添加了 import 语句) :

暂时重定向标准输出:

import sys
from contextlib import contextmanager
@contextmanager
def stdout_redirected(new_stdout):
    save_stdout = sys.stdout
    sys.stdout = new_stdout
    try:
        yield None
    finally:
        sys.stdout = save_stdout

用法如下:

with open(filename, "w") as f:
    with stdout_redirected(f):
        print "Hello world"

当然,这不是线程安全的,但手动执行相同的操作也不是。在单线程程序中(例如在脚本中),这是一种流行的处理方式。

Quoted from PEP 343 -- The "with" Statement (added import statement):

Redirect stdout temporarily:

import sys
from contextlib import contextmanager
@contextmanager
def stdout_redirected(new_stdout):
    save_stdout = sys.stdout
    sys.stdout = new_stdout
    try:
        yield None
    finally:
        sys.stdout = save_stdout

Used as follows:

with open(filename, "w") as f:
    with stdout_redirected(f):
        print "Hello world"

This isn't thread-safe, of course, but neither is doing this same dance manually. In single-threaded programs (for example in scripts) it is a popular way of doing things.

幸福丶如此 2024-10-18 10:17:28
import sys
sys.stdout = open('stdout.txt', 'w')
import sys
sys.stdout = open('stdout.txt', 'w')
空心↖ 2024-10-18 10:17:28

这是 Yuda Prarawa 答案的一个变体:

  • 实现 flush() 并且所有文件属性
  • 将其写为上下文管理器
  • 捕获 stderr

import contextlib, sys

@contextlib.contextmanager
def log_print(file):
    # capture all outputs to a log file while still printing it
    class Logger:
        def __init__(self, file):
            self.terminal = sys.stdout
            self.log = file

        def write(self, message):
            self.terminal.write(message)
            self.log.write(message)

        def __getattr__(self, attr):
            return getattr(self.terminal, attr)

    logger = Logger(file)

    _stdout = sys.stdout
    _stderr = sys.stderr
    sys.stdout = logger
    sys.stderr = logger
    try:
        yield logger.log
    finally:
        sys.stdout = _stdout
        sys.stderr = _stderr


with log_print(open('mylogfile.log', 'w')):
    print('hello world')
    print('hello world on stderr', file=sys.stderr)

# you can capture the output to a string with:
# with log_print(io.StringIO()) as log:
#   ....
#   print('[captured output]', log.getvalue())

Here is a variation of Yuda Prawira answer:

  • implement flush() and all the file attributes
  • write it as a contextmanager
  • capture stderr also

.

import contextlib, sys

@contextlib.contextmanager
def log_print(file):
    # capture all outputs to a log file while still printing it
    class Logger:
        def __init__(self, file):
            self.terminal = sys.stdout
            self.log = file

        def write(self, message):
            self.terminal.write(message)
            self.log.write(message)

        def __getattr__(self, attr):
            return getattr(self.terminal, attr)

    logger = Logger(file)

    _stdout = sys.stdout
    _stderr = sys.stderr
    sys.stdout = logger
    sys.stderr = logger
    try:
        yield logger.log
    finally:
        sys.stdout = _stdout
        sys.stderr = _stderr


with log_print(open('mylogfile.log', 'w')):
    print('hello world')
    print('hello world on stderr', file=sys.stderr)

# you can capture the output to a string with:
# with log_print(io.StringIO()) as log:
#   ....
#   print('[captured output]', log.getvalue())
惟欲睡 2024-10-18 10:17:28

您需要一个终端多路复用器,例如 tmuxGNU screen

我很惊讶 Ryan Amos 对原始问题的一个小评论是唯一提到的解决方案,远优于所有其他提供的解决方案,无论蟒蛇的诡计多么聪明,无论他们收到了多少支持。根据 Ryan 的评论,tmux 是 GNU screen 的一个很好的替代品。

但原理是相同的:如果您发现自己想在注销时让终端作业继续运行,请前往咖啡馆吃个三明治,去洗手间,回家(等等),然后重新连接到您的计算机。从任何地方或任何计算机进行终端会话就好像您从未离开过一样,终端多路复用器就是答案。将它们视为终端会话的 VNC 或远程桌面。其他任何方法都是解决方法。作为奖励,当老板和/或合作伙伴进来并且您无意中 ctrl-w / cmd-w 终端窗口而不是浏览器窗口及其可疑内容时,您不会丢失过去 18 小时的处理时间!

You need a terminal multiplexer like either tmux or GNU screen

I'm surprised that a small comment by Ryan Amos' to the original question is the only mention of a solution far preferable to all the others on offer, no matter how clever the python trickery may be and how many upvotes they've received. Further to Ryan's comment, tmux is a nice alternative to GNU screen.

But the principle is the same: if you ever find yourself wanting to leave a terminal job running while you log-out, head to the cafe for a sandwich, pop to the bathroom, go home (etc) and then later, reconnect to your terminal session from anywhere or any computer as though you'd never been away, terminal multiplexers are the answer. Think of them as VNC or remote desktop for terminal sessions. Anything else is a workaround. As a bonus, when the boss and/or partner comes in and you inadvertently ctrl-w / cmd-w your terminal window instead of your browser window with its dodgy content, you won't have lost the last 18 hours-worth of processing!

早乙女 2024-10-18 10:17:28

基于这个答案:https://stackoverflow.com/a/5916874/1060344,这是我想出的另一种方法我在我的一个项目中使用它。无论您用什么替换 sys.stderrsys.stdout,您都必须确保替换符合 file 接口,特别是如果是您正在做的事情,因为 stderr/stdout 在不受您控制的其他一些库中使用。该库可能正在使用文件对象的其他方法。

看看这种方式,我仍然让一切都去做 stderr/stdout (或任何与此相关的文件),并使用 Python 的日志记录工具将消息发送到日志文件(但你真的可以用它做任何事情):

class FileToLogInterface(file):
    '''
    Interface to make sure that everytime anything is written to stderr, it is
    also forwarded to a file.
    '''

    def __init__(self, *args, **kwargs):
        if 'cfg' not in kwargs:
            raise TypeError('argument cfg is required.')
        else:
            if not isinstance(kwargs['cfg'], config.Config):
                raise TypeError(
                    'argument cfg should be a valid '
                    'PostSegmentation configuration object i.e. '
                    'postsegmentation.config.Config')
        self._cfg = kwargs['cfg']
        kwargs.pop('cfg')

        self._logger = logging.getlogger('access_log')

        super(FileToLogInterface, self).__init__(*args, **kwargs)

    def write(self, msg):
        super(FileToLogInterface, self).write(msg)
        self._logger.info(msg)

Based on this answer: https://stackoverflow.com/a/5916874/1060344, here is another way I figured out which I use in one of my projects. For whatever you replace sys.stderr or sys.stdout with, you have to make sure that the replacement complies with file interface, especially if this is something you are doing because stderr/stdout are used in some other library that is not under your control. That library may be using other methods of file object.

Check out this way where I still let everything go do stderr/stdout (or any file for that matter) and also send the message to a log file using Python's logging facility (but you can really do anything with this):

class FileToLogInterface(file):
    '''
    Interface to make sure that everytime anything is written to stderr, it is
    also forwarded to a file.
    '''

    def __init__(self, *args, **kwargs):
        if 'cfg' not in kwargs:
            raise TypeError('argument cfg is required.')
        else:
            if not isinstance(kwargs['cfg'], config.Config):
                raise TypeError(
                    'argument cfg should be a valid '
                    'PostSegmentation configuration object i.e. '
                    'postsegmentation.config.Config')
        self._cfg = kwargs['cfg']
        kwargs.pop('cfg')

        self._logger = logging.getlogger('access_log')

        super(FileToLogInterface, self).__init__(*args, **kwargs)

    def write(self, msg):
        super(FileToLogInterface, self).write(msg)
        self._logger.info(msg)
丑疤怪 2024-10-18 10:17:28

用其他语言(例如 C)编写的程序必须明确地执行特殊的魔法(称为双分叉)以从终端分离(并防止僵尸进程)。所以,我认为最好的解决办法就是效仿他们。

重新执行程序的一个优点是,您可以在命令行上选择重定向,例如 /usr/bin/python mycoolscript.py 2>&1 1>/dev/null

请参阅此发布更多信息:什么创建守护进程时执行双分叉的原因是什么?

Programs written in other languages (e.g. C) have to do special magic (called double-forking) expressly to detach from the terminal (and to prevent zombie processes). So, I think the best solution is to emulate them.

A plus of re-executing your program is, you can choose redirections on the command-line, e.g. /usr/bin/python mycoolscript.py 2>&1 1>/dev/null

See this post for more info: What is the reason for performing a double fork when creating a daemon?

假扮的天使 2024-10-18 10:17:28

我知道这个问题已经得到解答(使用 python abc.py > output.log 2>&1 ),但我仍然不得不说:

编写程序时,不要写入标准输出。始终使用日志记录来输出您想要的任何内容。当您将来想要重定向、过滤、旋转输出文件时,这将为您提供很大的自由。

I know this question is answered (using python abc.py > output.log 2>&1 ), but I still have to say:

When writing your program, don't write to stdout. Always use logging to output whatever you want. That would give you a lot of freedom in the future when you want to redirect, filter, rotate the output files.

嘦怹 2024-10-18 10:17:28

正如 @jfs 所提到的,大多数解决方案都无法正确处理某些类型的 stdout 输出,例如来自 C 扩展的输出。 PyPI 上有一个名为 wurlitzer 的模块负责处理所有这些事情。您只需要它的 sys_pipes 上下文管理器。就像使用一样简单:

from contextlib import redirect_stdout
import os
from wurlitzer import sys_pipes
        
log = open("test.log", "a")
with redirect_stdout(log), sys_pipes():
    print("print statement")
    os.system("echo echo call")

As mentioned by @jfs, most solutions will not properly handle some types of stdout output such as that from C extensions. There is a module that takes care of all this on PyPI called wurlitzer. You just need its sys_pipes context manager. It's as easy as using:

from contextlib import redirect_stdout
import os
from wurlitzer import sys_pipes
        
log = open("test.log", "a")
with redirect_stdout(log), sys_pipes():
    print("print statement")
    os.system("echo echo call")
原来是傀儡 2024-10-18 10:17:28

根据这篇文章之前的答案,我为自己编写了这个类,作为一种更紧凑、更灵活的方式来重定向代码段的输出(这里只是到一个列表),并确保之后输出标准化。

class out_to_lt():
    def __init__(self, lt):
        if type(lt) == list:
            self.lt = lt
        else:
            raise Exception("Need to pass a list")            
    def __enter__(self):
        import sys
        self._sys = sys
        self._stdout = sys.stdout
        sys.stdout = self
        return self
    def write(self,txt):
        self.lt.append(txt)    
    def __exit__(self, type, value, traceback):
        self._sys.stdout = self._stdout

用作:

lt = []
with out_to_lt(lt) as o:
    print("Test 123\n\n")
    print(help(str))

更新。刚刚发现一个场景,我必须添加两个额外的方法,但很容易适应:

class out_to_lt():
    ...
    def isatty(self):
        return True #True: You're running in a real terminal, False:You're being piped, redirected, cron
    def flush(self):
        pass

Based on previous answers on this post I wrote this class for myself as a more compact and flexible way of redirecting the output of pieces of code - here just to a list - and ensure that the output is normalized afterwards.

class out_to_lt():
    def __init__(self, lt):
        if type(lt) == list:
            self.lt = lt
        else:
            raise Exception("Need to pass a list")            
    def __enter__(self):
        import sys
        self._sys = sys
        self._stdout = sys.stdout
        sys.stdout = self
        return self
    def write(self,txt):
        self.lt.append(txt)    
    def __exit__(self, type, value, traceback):
        self._sys.stdout = self._stdout

Used as:

lt = []
with out_to_lt(lt) as o:
    print("Test 123\n\n")
    print(help(str))

Updating. Just found a scenario where I had to add two extra methods, but was easy to adapt:

class out_to_lt():
    ...
    def isatty(self):
        return True #True: You're running in a real terminal, False:You're being piped, redirected, cron
    def flush(self):
        pass
○闲身 2024-10-18 10:17:28

还有其他使用上下文的版本,但没有这么简单。实际上,我只是在谷歌上仔细检查它是否有效,但很惊讶没有看到它,因此对于其他正在寻找安全且仅针对上下文块中的代码的快速解决方案的人来说,这里是:

import sys
with open('test_file', 'w') as sys.stdout:
    print('Testing 1 2 3')

测试如下:

$catredirect_stdout.py
导入系统

将 open('test_file', 'w') 作为 sys.stdout:
    print('测试 1 2 3')
$ pythonredirect_stdout.py
$ 猫测试文件
测试 1 2 3

There are other versions using context but nothing this simple. I actually just googled to double check it would work and was surprised not to see it, so for other people looking for a quick solution that is safe and directed at only the code within the context block, here it is:

import sys
with open('test_file', 'w') as sys.stdout:
    print('Testing 1 2 3')

Tested like so:

$ cat redirect_stdout.py
import sys

with open('test_file', 'w') as sys.stdout:
    print('Testing 1 2 3')
$ python redirect_stdout.py
$ cat test_file
Testing 1 2 3
耳根太软 2024-10-18 10:17:28

对于那些感兴趣的人,我扩展了这个问题。我需要写入日志文件一段时间,然后关闭它,重命名它并随后使用正常的标准输出。我该怎么做?

print("Start program")
import os
import sys
sys.stdout.flush()
sys.stdout=open("xxxtmp", "wt")
print("xxx")
sys.stdout.close()
sys.stdout = sys.__stdout__
os.rename("xxxtmp", "xxx")
print("End program")

在stdout上会有:

Start program
End program

在xxx上会有:

xxx

如果程序异常退出,xxx文件将不存在。

For those interested, I extend the question. I need to write to log file for a while, then close it, rename it and use normal stdout afterwards. How do I do it?

print("Start program")
import os
import sys
sys.stdout.flush()
sys.stdout=open("xxxtmp", "wt")
print("xxx")
sys.stdout.close()
sys.stdout = sys.__stdout__
os.rename("xxxtmp", "xxx")
print("End program")

On stdout there will be:

Start program
End program

In xxx there will be:

xxx

If the program exits abnormally, the xxx file won't exist.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文