5

I'm trying to store the output of a Function into a file in Python, what I am trying to do is something like this:

def test():
        print("This is a Test")
file=open('Log','a')
file.write(test())
file.close()

But when I do this I get this error:

TypeError: argument 1 must be string or read-only character buffer, not None

PD: I'm trying to do this for a function I can't modify.

4
  • You want to capture stdin output in case of example you posted Commented Aug 25, 2017 at 16:36
  • Yes, for example, in what I posted above, I would like to store "This is a Test" in a file called "Log" Commented Aug 25, 2017 at 16:38
  • check this answer if it helps: stackoverflow.com/a/30942680/8427155 Commented Aug 25, 2017 at 16:42
  • Yes it worked. Thank you a lot. Commented Aug 25, 2017 at 16:45

5 Answers 5

14

Whenever any operation would need to be performed in pairs, use a context manager.

In this case, use contextlib.redirect_stdout:

with open('Log','a') as f:
    with contextlib.redirect_stdout(f):
        test()

Edit: if you want it as a string, use io.StringIO:

f = io.StringIO()
with contextlib.redirect_stdout(f):
    test()
s = f.getvalue()
Sign up to request clarification or add additional context in comments.

6 Comments

Excellent answer, BTW, to avoid of using nested WITH Statement, we can use ExitStack
@AntoineFontaine question is tagged python3, and nobody uses 3.2 or 3.3 anymore.
To be fair it is also tagged just python and there are a lot of people still using python 2.n despite what your preference may be.
Well, there's always the contextlib2 module on Pypi ... really, anyone still using Python2 should be used to hunting down backports.
perfect! Was searching for this for a while :=
|
1

You need to redirect the standard output by assigning it an object implementing the write method, like a file.

import sys

def test():
    print("This is a Test")

stdout_backup = sys.stdout

with open('Log', 'a') as f:
    sys.stdout = f
    test()

sys.stdout = stdout_backup

Comments

1

Solution 1:

Instead of using print, you should use logging to do this:

import logging

logger = logging.getLogger('myapp')
hdlr = logging.FileHandler('/tmp/myapp.log')
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)

def test():
    logger.info("This is a Test")

test()

the codes above works fine, you can use it. PS: check the output in file /tmp/myapp.log

Solution 2:

just run your codes in command line, and store all the output into a file 'text.log'

python main.py >> text.log

Solution 3:

import contextlib
from contextlib import ExitStack


def test():
    print('hello world')


with ExitStack() as stack:
    f = stack.enter_context(open('Log', 'a'))
    stack.enter_context(contextlib.redirect_stdout(f))
    test()

print("I'm not logged")

3 Comments

Yes, but that would need me to modify the function itself, and I am not able to modify it, that function prints out some output I need to store on a file.
Is solution 2 ok for you?
That would give me the whole output of the script not just for the function, I just need the function.
1

you can define a decorator based on @o11c answer:

def redirect_output_to_file(fname, overwrite=False):
    def real_redirect_output_to_file(func):
        def wrapper(*args, **kwargs):
            import contextlib
            with open(fname, 'w' if overwrite else 'a') as f:
                with contextlib.redirect_stdout(f):
                    retval = func(*args, **kwargs)
            return retval
        return wrapper
    return real_redirect_output_to_file

And then use it on any function:

@redirect_output_to_file('test_output.log')
def test():
   print('Hi')

Comments

0

Is the function in the same file? becuase it is was you could do something like this

Solution 1:

import sys

def test():
        print("This is a test") 

out = sys.stdout
with open("Log", "a") as output:
    sys.stdout = output
    test()
sys.stdout = out 

gives

[Program finished]

contents in file,

This is a test
This is a test

The issue is that the function only prints, but doesn't return anything. Python 3.4 added https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout which allows you to redirect stdout to a file:

Solution 2:

PS C:\Users\tan\Desktop> cat stdout.py
def test():
  print("This is a Test")

from contextlib import redirect_stdout

with open('stdout.txt', 'w') as f:
  with redirect_stdout(f):
    test()

print('stdout in console again')
PS C:\Users\tan\Desktop> python .\stdout.py
stdout in console again
PS C:\Users\tan\Desktop> cat stdout.txt
This is a Test 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.