There are several ways to write to stderr:
print >> sys.stderr, "spam" # Python 2 only.
sys.stderr.write("spam\n")
os.write(2, b"spam\n")
from __future__ import print_function
print("spam", file=sys.stderr)
What are the differences between these methods? Which method should be preferred?
I found this to be the only one short, flexible, portable and readable:
import sys
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
The optional function eprint saves some repetition. It can be used in the same way as the standard print function:
>>> print("Test")
Test
>>> eprint("Test")
Test
>>> eprint("foo", "bar", "baz", sep="---")
foo---bar---baz
import sys
sys.stderr.write()
Is my choice, just more readable and saying exactly what you intend to do and portable across versions.
Edit: being 'pythonic' is a third thought to me over readability and performance... with these two things in mind, with python 80% of your code will be pythonic. list comprehension being the 'big thing' that isn't used as often (readability).
Python 3:
print("fatal error", file=sys.stderr)
Python 2:
print >> sys.stderr, "fatal error"
Long answer
print >> sys.stderr is gone in Python3.
http://docs.python.org/3.0/whatsnew/3.0.html says:
Old: print >> sys.stderr, "fatal error"
New: print("fatal error", file=sys.stderr)
For many of us, it feels somewhat unnatural to relegate the destination to the end of the command. The alternative
sys.stderr.write("fatal error\n")
looks more object oriented, and elegantly goes from the generic to the specific. But note that write is not a 1:1 replacement for print.
Nobody's mentioned logging yet, but logging was created specifically to communicate error messages. Basic configuration will set up a stream handler writing to stderr.
This script:
# foo.py
import logging
logging.basicConfig(format='%(message)s')
log = logging.getLogger(__name__)
log.warning('I print to stderr by default')
print('hello world')
has the following result when run on the command line:
$ python3 foo.py > bar.txt
I print to stderr by default
and bar.txt will contain the 'hello world' printed on stdout.
For Python 2 my choice is:
print >> sys.stderr, 'spam'
Because you can simply print lists/dicts etc. without convert it to string.
print >> sys.stderr, {'spam': 'spam'}
instead of:
sys.stderr.write(str({'spam': 'spam'}))
I would say that your first approach:
print >> sys.stderr, 'spam'
is the "One . . . obvious way to do it" The others don't satisfy rule #1 ("Beautiful is better than ugly.")
-- Edit for 2020 --
Above was my answer for Python 2.7 in 2011. Now that Python 3 is the standard, I think the "right" answer is:
print("spam", file=sys.stderr)
I did the following using Python 3:
from sys import stderr
def print_err(*args, **kwargs):
print(*args, file=stderr, **kwargs)
So now I'm able to add keyword arguments, for example, to avoid carriage return:
print_err("Error: end of the file reached. The word ", end='')
print_err(word, "was not found")
In Python 3, one can just use print():
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
almost out of the box:
import sys
print("Hello, world!", file=sys.stderr)
or:
from sys import stderr
print("Hello, world!", file=stderr)
This is straightforward and does not need to include anything besides sys.stderr.
This will mimic the standard print function but output on stderr
def print_err(*args):
sys.stderr.write(' '.join(map(str,args)) + '\n')
EDIT In hind-sight, I think the potential confusion with changing sys.stderr and not seeing the behaviour updated makes this answer not as good as just using a simple function as others have pointed out.
Using partial only saves you 1 line of code. The potential confusion is not worth saving 1 line of code.
original
To make it even easier, here's a version that uses 'partial', which is a big help in wrapping functions.
from __future__ import print_function
import sys
from functools import partial
error = partial(print, file=sys.stderr)
You then use it like so
error('An error occured!')
You can check that it's printing to stderr and not stdout by doing the following (over-riding code from http://coreygoldberg.blogspot.com.au/2009/05/python-redirect-or-turn-off-stdout-and.html):
# over-ride stderr to prove that this function works.
class NullDevice():
def write(self, s):
pass
sys.stderr = NullDevice()
# we must import print error AFTER we've removed the null device because
# it has been assigned and will not be re-evaluated.
# assume error function is in print_error.py
from print_error import error
# no message should be printed
error("You won't see this error!")
The downside to this is partial assigns the value of sys.stderr to the wrapped function at the time of creation. Which means, if you redirect stderr later it won't affect this function.
If you plan to redirect stderr, then use the **kwargs method mentioned by aaguirre on this page.
The same applies to stdout:
print 'spam'
sys.stdout.write('spam\n')
As stated in the other answers, print offers a pretty interface that is often more convenient (e.g. for printing debug information), while write is faster and can also be more convenient when you have to format the output exactly in certain way. I would consider maintainability as well:
You may later decide to switch between stdout/stderr and a regular file.
print() syntax has changed in Python 3, so if you need to support both versions, write() might be better.
I am working in python 3.4.3. I am cutting out a little typing that shows how I got here:
[18:19 jsilverman#JSILVERMAN-LT7 pexpect]$ python3
>>> import sys
>>> print("testing", file=sys.stderr)
testing
>>>
[18:19 jsilverman#JSILVERMAN-LT7 pexpect]$
Did it work? Try redirecting stderr to a file and see what happens:
[18:22 jsilverman#JSILVERMAN-LT7 pexpect]$ python3 2> /tmp/test.txt
>>> import sys
>>> print("testing", file=sys.stderr)
>>> [18:22 jsilverman#JSILVERMAN-LT7 pexpect]$
[18:22 jsilverman#JSILVERMAN-LT7 pexpect]$ cat /tmp/test.txt
Python 3.4.3 (default, May 5 2015, 17:58:45)
[GCC 4.9.2] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
testing
[18:22 jsilverman#JSILVERMAN-LT7 pexpect]$
Well, aside from the fact that the little introduction that python gives you has been slurped into stderr (where else would it go?), it works.
If you want to exit a program because of a fatal error, use:
sys.exit("Your program caused a fatal error. ... description ...")
and import sys in the header.
If you do a simple test:
import time
import sys
def run1(runs):
x = 0
cur = time.time()
while x < runs:
x += 1
print >> sys.stderr, 'X'
elapsed = (time.time()-cur)
return elapsed
def run2(runs):
x = 0
cur = time.time()
while x < runs:
x += 1
sys.stderr.write('X\n')
sys.stderr.flush()
elapsed = (time.time()-cur)
return elapsed
def compare(runs):
sum1, sum2 = 0, 0
x = 0
while x < runs:
x += 1
sum1 += run1(runs)
sum2 += run2(runs)
return sum1, sum2
if __name__ == '__main__':
s1, s2 = compare(1000)
print "Using (print >> sys.stderr, 'X'): %s" %(s1)
print "Using (sys.stderr.write('X'),sys.stderr.flush()):%s" %(s2)
print "Ratio: %f" %(float(s1) / float(s2))
You will find that sys.stderr.write() is consistently 1.81 times faster!
Answer to the question is : There are different way to print stderr in python but that depends on
1.) which python version we are using
2.) what exact output we want.
The differnce between print and stderr's write function:
stderr : stderr (standard error) is pipe that is built into every UNIX/Linux system, when your program crashes and prints out debugging information (like a traceback in Python), it goes to the stderr pipe.
print: print is a wrapper that formats the inputs (the input is the space between argument and the newline at the end) and it then calls the write function of a given object, the given object by default is sys.stdout, but we can pass a file i.e we can print the input in a file also.
Python2:
If we are using python2 then
>>> import sys
>>> print "hi"
hi
>>> print("hi")
hi
>>> print >> sys.stderr.write("hi")
hi
Python2 trailing comma has in Python3 become a parameter, so if we use
trailing commas to avoid the newline after a print, this will in
Python3 look like print('Text to print', end=' ') which is a syntax
error under Python2.
http://python3porting.com/noconv.html
If we check same above sceario in python3:
>>> import sys
>>> print("hi")
hi
Under Python 2.6 there is a future import to make print into a
function. So to avoid any syntax errors and other differences we
should start any file where we use print() with from future import
print_function. The future import only works under Python 2.6 and
later, so for Python 2.5 and earlier you have two options. You can
either convert the more complex print to something simpler, or you can
use a separate print function that works under both Python2 and
Python3.
>>> from __future__ import print_function
>>>
>>> def printex(*args, **kwargs):
... print(*args, file=sys.stderr, **kwargs)
...
>>> printex("hii")
hii
>>>
Case: Point to be noted that sys.stderr.write() or sys.stdout.write()
( stdout (standard output) is a pipe that is built into every
UNIX/Linux system) is not a replacement for print, but yes we can use
it as a alternative in some case. Print is a wrapper which wraps the
input with space and newline at the end and uses the write function to
write. This is the reason sys.stderr.write() is faster.
Note: we can also trace and debugg using Logging
#test.py
import logging
logging.info('This is the existing protocol.')
FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logging.warning("Protocol problem: %s", "connection reset", extra=d)
https://docs.python.org/2/library/logging.html#logger-objects
Im doing this just for fun but here is another way... :-)
message = 'error: Belly up!!'
print(message, file=sys.stderr if 'error' in message.lower() else sys.stdout)
Another way
import sys
print("{}".format(sys.exec_info()[1], file=sys.stderr)
Related
Now I use:
pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()
But to make the code look better, I can do:
output = open('pagehead.section.htm','r').read()
When using the above syntax, how do I close the file to free up system resources?
You don't really have to close it - Python will do it automatically either during garbage collection or at program exit. But as #delnan noted, it's better practice to explicitly close it for various reasons.
So, what you can do to keep it short, simple and explicit:
with open('pagehead.section.htm', 'r') as f:
output = f.read()
Now it's just two lines and pretty readable, I think.
Python Standard Library Pathlib module does what you looking for:
Path('pagehead.section.htm').read_text()
Don't forget to import Path:
jsk#dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'
On Python 27 install backported pathlib or pathlib2
Using CPython, your file will be closed immediately after the line is executed, because the file object is immediately garbage collected. There are two drawbacks, though:
In Python implementations different from CPython, the file often isn't immediately closed, but rather at a later time, beyond your control.
In Python 3.2 or above, this will throw a ResourceWarning, if enabled.
Better to invest one additional line:
with open('pagehead.section.htm','r') as f:
output = f.read()
This will ensure that the file is correctly closed under all circumstances.
No need to import any special libraries to do this.
Use normal syntax and it will open the file for reading then close it.
with open("/etc/hostname","r") as f: print f.read()
or
with open("/etc/hosts","r") as f: x = f.read().splitlines()
which gives you an array x containing the lines, and can be printed like so:
for line in x: print line
These one-liners are very helpful for maintenance - basically self-documenting.
What you can do is to use the with statement, and write the two steps on one line:
>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content
The with statement will take care to call __exit__ function of the given object even if something bad happened in your code; it's close to the try... finally syntax. For object returned by open, __exit__ corresponds to file closure.
This statement has been introduced with Python 2.6.
use ilio: (inline io):
just one function call instead of file open(), read(), close().
from ilio import read
content = read('filename')
I think the most natural way for achieving this is to define a function.
def read(filename):
f = open(filename, 'r')
output = f.read()
f.close()
return output
Then you can do the following:
output = read('pagehead.section.htm')
with open('pagehead.section.htm')as f:contents=f.read()
I frequently do something like this when I need to get a few lines surrounding something I've grepped in a log file:
$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54
$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5
Using more_itertools.with_iter, it is possible to open, read, close and assign an equivalent output in one line (excluding the import statement):
import more_itertools as mit
output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))
Although possible, I would look for another approach other than assigning the contents of a file to a variable, i.e. lazy iteration - this can be done using a traditional with block or in the example above by removing join() and iterating output.
If you want that warm and fuzzy feeling just go with with.
For python 3.6 I ran these two programs under a fresh start of IDLE, giving runtimes of:
0.002000093460083008 Test A
0.0020003318786621094 Test B: with guaranteed close
So not much of a difference.
#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*
import sys
import time
# # MAINLINE
if __name__ == '__main__':
print("OK, starting program...")
inTextFile = '/Users/Mike/Desktop/garbage.txt'
# # Test: A: no 'with;
c=[]
start_time = time.time()
c = open(inTextFile).read().splitlines()
print("--- %s seconds ---" % (time.time() - start_time))
print("OK, program execution has ended.")
sys.exit() # END MAINLINE
OUTPUT:
OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.
#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*
import sys
import time
# # MAINLINE
if __name__ == '__main__':
print("OK, starting program...")
inTextFile = '/Users/Mike/Desktop/garbage.txt'
# # Test: B: using 'with'
c=[]
start_time = time.time()
with open(inTextFile) as D: c = D.read().splitlines()
print("--- %s seconds ---" % (time.time() - start_time))
print("OK, program execution has ended.")
sys.exit() # END MAINLINE
OUTPUT:
OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
I'm working on a large codebase that uses print statements for logging rather than python logging. I'm wondering if there is a recommended for converting all these print statements to calls to logging.info? Many of these prints are spread over several lines and thus any solution needs to handle those cases and hopefully would maintain formatting.
I've looked into python rope but that doesn't seem to have the facility to convert calls to statement like print to a function call.
You could use 2to3 and only apply the fix for print statement -> print function.
2to3 --fix=print [yourfiles] # just displays the diff on stdout
2to3 --fix=print [yourfiles] --write # also saves the changes to disk
This should automatically handle all those strange cases, and then converting print functions to logging functions should be a straightforward find-and-replace with, e.g., sed.
If you don't have the shortcut for the 2to3 script for some reason, run lib2to3 as a module instead:
python -m lib2to3 --fix=print .
just add this few line before your code starts and it will log everything it prints. I think you are looking for something like this.
import logging
import sys
class writer :
def __init__(self, *writers) :
self.writers = writers
def write(self, text) :
logging.warning(text)
saved = sys.stdout
sys.stdout = writer(sys.stdout)
print "There you go."
print "There you go2."
I have a python program of about 500 lines that writes to stdout (using print statements). Now I'd like to make some changes and do refactoring of the program, but I want to make sure that in the process of doing so I keep getting the same output (given the same input, of course).
What would be a good strategy to do so, without rewriting the functions to return strings (allowing for easier testing) instead of the current print-ing?
I though of redirecting the initial output (before I start changing it) to a text file. How can I then easily and automatically check the output of the modified program with the textfile (without redirecting that output again to a temporary text file and comparing the files)?
Edit: This is the solution I settled on:
def test_something():
# using lambda because we might test function with parameters
f = lambda: thing_to_test
test_generic('expect_output.txt', f)
def test_generic(filename_expected, function_to_test):
#Run and write to tmp file
tmpfile = 'test-tmp.txt'
sys.stdout = open(tmpfile, 'w')
function_to_test()
sys.stdout = sys.__stdout__
#compare with expected output
expected = open(filename_expected).read()
result = open(tmpfile).read()
d = difflib.Differ()
diff = d.compare(expected.splitlines(), result.splitlines())
#print result (different lines only)
diff_lines_only = [line for line in diff if line[0] in "+-?"]
if not diff_lines_only:
print "Test succeeded (%s)\n" % filename_expected
os.remove(tmpfile)
else:
print "Test FAILED (%s):\n" % filename_expected
print '\n'.join(list(diff_lines))
Edit 2: Actually, I think the doctest solution which I provided as an answer below is much nicer.
You can obtain the string representing the output of your program redirecting sys.stdout.
To compare the outputs you can use the difflib module. In particular the Differ class does more or less what the diff command does:
>>> import difflib
>>> text = '''bar
... baz
... '''
>>> text2 = '''foo
... bar
... '''
>>> d = difflib.Differ()
>>> for line in d.compare(text.splitlines(), text2.splitlines()):
... print line
...
+ foo
bar
- baz
If I'm not mistaken unittest2's assertEqual already tries to show the difference of the strings, but I do not know at what level and if the output is simple enough.
Assuming you're running Bash, you could run diff -u orig-file <(python my-program.py). This will do a diff between the original file (which you've already written your original output to), and a named pipe that your program will write out to.
Here's a quick trivial example, using echo instead of an actual Python script:
$ diff -u <(echo $'foo\nbar\nbaz') <(echo $'foo\nbar\nquux')
--- /dev/fd/63 2012-11-08 15:07:09.000000000 -0500
+++ /dev/fd/62 2012-11-08 15:07:09.000000000 -0500
## -1,3 +1,3 ##
foo
bar
-baz
+quux
Interesting little example question - i took it to create a print/capture/diffcompare solution using pytest. Note that this example makes advanced use of pytest features but those are linked and fully documented and are useful also in many other situations. Effectively, the solution needs less than half the code of the current top solution and you may find it nice to be able to selectively run tests or some of the other other pytest features.
A solution using the doctest library, which I consider actually much nicer and self-contained as the test code and the expected output are now together in one file.
In a python script (actually, I included it in my main program, and is executed if I provide "test" as a first command line argument):
import doctest
doctest.testfile('test-program.txt', optionflags = doctest.NORMALIZE_WHITESPACE)
And the test file test-program.txt now goes along the lines of:
>>> import my_python_script
>>> whatever_I want_to_test_or_call_goes_here
and_here_I pasted_the_expected_output
This has the added benefit of having access to all doctest features (such as the -v switch for more verbose output). So I just do the following from the command line to get a full report:
C:\wherever> python my_python_script test -v
I know the --verbose or -v from several tools and I'd like to implement this into some of my own scripts and tools.
I thought of placing:
if verbose:
print ...
through my source code, so that if a user passes the -v option, the variable verbose will be set to True and the text will be printed.
Is this the right approach or is there a more common way?
Addition: I am not asking for a way to implement the parsing of arguments. That I know how it is done. I am only interested specially in the verbose option.
My suggestion is to use a function. But rather than putting the if in the function, which you might be tempted to do, do it like this:
if verbose:
def verboseprint(*args):
# Print each argument separately so caller doesn't need to
# stuff everything to be printed into a single string
for arg in args:
print arg,
print
else:
verboseprint = lambda *a: None # do-nothing function
(Yes, you can define a function in an if statement, and it'll only get defined if the condition is true!)
If you're using Python 3, where print is already a function (or if you're willing to use print as a function in 2.x using from __future__ import print_function) it's even simpler:
verboseprint = print if verbose else lambda *a, **k: None
This way, the function is defined as a do-nothing if verbose mode is off (using a lambda), instead of constantly testing the verbose flag.
If the user could change the verbosity mode during the run of your program, this would be the wrong approach (you'd need the if in the function), but since you're setting it with a command-line flag, you only need to make the decision once.
You then use e.g. verboseprint("look at all my verbosity!", object(), 3) whenever you want to print a "verbose" message.
If you are willing and able to use the Python -O flag to turn verbosity on and off when launching the "production" version of the script (or set the PYTHONOPTIMIZE environment variable) then the better way is to test the __debug__ flag everywhere you want to print a verbose output:
if __debug__: print("Verbosity enabled")
When run without optimization, these statements are executed (and the if is stripped out, leaving only the body of the statement). When run with optimization, Python actually strips those statements out entirely. They have no performance impact whatsoever! See my blog post on __debug__ and -O for a more in-depth discussion.
Use the logging module:
import logging as log
…
args = p.parse_args()
if args.verbose:
log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
log.info("Verbose output.")
else:
log.basicConfig(format="%(levelname)s: %(message)s")
log.info("This should be verbose.")
log.warning("This is a warning.")
log.error("This is an error.")
All of these automatically go to stderr:
% python myprogram.py
WARNING: This is a warning.
ERROR: This is an error.
% python myprogram.py -v
INFO: Verbose output.
INFO: This should be verbose.
WARNING: This is a warning.
ERROR: This is an error.
For more info, see the Python Docs and the tutorials.
Building and simplifying #kindall's answer, here's what I typically use:
v_print = None
def main()
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbosity', action="count",
help="increase output verbosity (e.g., -vv is more than -v)")
args = parser.parse_args()
if args.verbosity:
def _v_print(*verb_args):
if verb_args[0] > (3 - args.verbosity):
print verb_args[1]
else:
_v_print = lambda *a: None # do-nothing function
global v_print
v_print = _v_print
if __name__ == '__main__':
main()
This then provides the following usage throughout your script:
v_print(1, "INFO message")
v_print(2, "WARN message")
v_print(3, "ERROR message")
And your script can be called like this:
% python verbose-tester.py -v
ERROR message
% python verbose=tester.py -vv
WARN message
ERROR message
% python verbose-tester.py -vvv
INFO message
WARN message
ERROR message
A couple notes:
Your first argument is your error level, and the second is your message. It has the magic number of 3 that sets the upper bound for your logging, but I accept that as a compromise for simplicity.
If you want v_print to work throughout your program, you have to do the junk with the global. It's no fun, but I challenge somebody to find a better way.
What I do in my scripts is check at runtime if the 'verbose' option is set, and then set my logging level to debug. If it's not set, I set it to info. This way you don't have 'if verbose' checks all over your code.
I stole the logging code from virtualenv for a project of mine. Look in main() of virtualenv.py to see how it's initialized. The code is sprinkled with logger.notify(), logger.info(), logger.warn(), and the like. Which methods actually emit output is determined by whether virtualenv was invoked with -v, -vv, -vvv, or -q.
It might be cleaner if you have a function, say called vprint, that checks the verbose flag for you. Then you just call your own vprint function any place you want optional verbosity.
#kindall's solution does not work with my Python version 3.5. #styles correctly states in his comment that the reason is the additional optional keywords argument. Hence my slightly refined version for Python 3 looks like this:
if VERBOSE:
def verboseprint(*args, **kwargs):
print(*args, **kwargs)
else:
verboseprint = lambda *a, **k: None # do-nothing function
There could be a global variable, likely set with argparse from sys.argv, that stands for whether the program should be verbose or not.
Then a decorator could be written such that if verbosity was on, then the standard input would be diverted into the null device as long as the function were to run:
import os
from contextlib import redirect_stdout
verbose = False
def louder(f):
def loud_f(*args, **kwargs):
if not verbose:
with open(os.devnull, 'w') as void:
with redirect_stdout(void):
return f(*args, **kwargs)
return f(*args, **kwargs)
return loud_f
#louder
def foo(s):
print(s*3)
foo("bar")
This answer is inspired by this code; actually, I was going to just use it as a module in my program, but I got errors I couldn't understand, so I adapted a portion of it.
The downside of this solution is that verbosity is binary, unlike with logging, which allows for finer-tuning of how verbose the program can be.
Also, all print calls are diverted, which might be unwanted for.
What I need is a function which prints an object (obj), but only if global variable verbose is true, else it does nothing.
I want to be able to change the global parameter "verbose" at any time. Simplicity and readability to me are of paramount importance. So I would proceed as the following lines indicate:
ak#HP2000:~$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> verbose = True
>>> def vprint(obj):
... if verbose:
... print(obj)
... return
...
>>> vprint('Norm and I')
Norm and I
>>> verbose = False
>>> vprint('I and Norm')
>>>
Global variable "verbose" can be set from the parameter list, too.
I'm running Python 2.4 in a game engine and I want to be able to turn off all prints if needed. For example I'd like to have the prints on for a debug build, and then turned off for a release build.
It's also imperative that it's as transparent as possible.
My solution to this in the C code of the engine is having the printf function inside a vararg macro, and defining that to do nothing in a release build.
This is my current solution:
DebugPrints = True
def PRINT (*args):
global DebugPrints
if DebugPrints:
string = ""
for arg in args:
string += " " + str(arg)
print string
It makes it easy to toggle print outs, but there is possibly a better way to format the string. My main issue is that this is actually adding a lot more function calls to the program.
I'm wondering if there is anything you can do to how the print keyword works?
yes, you can assign sys.stdout to whatever you want. Create a little class with a write method that does nothing:
class DevNull(object):
def write(self, arg):
pass
import sys
sys.stdout = DevNull()
print "this goes to nirvana!"
With the same technique you can also have your prints logged to a file by setting sys.stdout to an opened file object.
I know an answer has already been marked as correct, but Python has a debug flag that provides a cleaner solution. You use it like this:
if __debug__:
print "whoa"
If you invoke Python with -O or -OO (as you normally would for a release build), __debug__ is set to False. What's even better is that __debug__ is a special case for the interpreter; it will actually strip out that code when it writes the pyc/pyo files, making the resulting code smaller/faster. Note that you can't assign values to __debug__, so it's entirely based off those command-line arguments.
The logging module is the "best" way.. although I quite often just use something simple like..
class MyLogger:
def _displayMessage(self, message, level = None):
# This can be modified easily
if level is not None:
print "[%s] %s" % (level, message
else:
print "[default] %s" % (message)
def debug(self, message):
self._displayMessage(message, level = "debug")
def info(self, message):
self._displayMessage(message, level = "info")
log = MyLogger()
log.info("test")
Don't use print, but make a console class which handles all printing. Simply make calls to the console and the console can decide whether or not to actually print them. A console class is also useful for things like error and warning messages or redirecting where the output goes.
If you really want to toggle printing:
>>> import sys
>>> import os
>>> print 'foo'
foo
>>> origstdout = sys.stdout
>>> sys.stdout = open(os.devnull, 'w')
>>> print 'foo'
>>> sys.stdout = origstdout
>>> print 'foo'
foo
However, I recommend you only use print for throwaway code. Use logging for real apps like the original question describes. It allows for a sliding scale of verbosity, so you can have only the important logging, or more verbose logging of usually less important details.
>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> logging.debug('foo')
DEBUG:root:foo
For example, usage might be to put debugging logs throughout your code. Then to silence them, change your level to a higher level, one of INFO, WARN or WARNING, ERROR, or CRITICAL or FATAL
>>> logging.root.setLevel(logging.INFO)
>>> logging.debug('foo')
>>>
In a script you'll want to just set this in the basicConfig like this:
import logging
logging.basicConfig(level=logging.INFO)
logging.debug('foo') # this will be silent
More sophisticated usage of logging can be found in the docs.
I've answered this question on a different post but was the question was marked duplicate:
anyhow, here's what I would do:
from __future__ import print_function
DebugPrints = 0
def print(*args, **kwargs):
if DebugPrints:
return __builtins__.print(*args, **kwargs)
print('foo') # doesn't get printed
DebugPrints = 1
print('bar') # gets printed
sadly you can't keep the py2 print syntax print 'foo'