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'
Related
Edit: My first attempt at asking this might be a bit unfocused/poorly worded here's a better explanation of what I'm trying to do:
I'm trying to modify the default behavior of the print function for the entire environment python is running in without having to modify each file that's being run.
I'm attempting to decorate the print function (I know there are many ways to do this such as overriding it but that's not really the question I'm asking) so I can have it print out some debugging information and force it to always flush. I did that like so:
def modify_print(func):
# I made this so that output always gets flushed as it won't by default
# within the environment I'm using, I also wanted it to print out some
# debugging information, doesn't really matter much in the context of this
# question
def modified_print(*args,**kwargs):
return func(f"some debug prefix: ",flush=True,*args,**kwargs)
return modified_print
print = modify_print(print)
print("Hello world") # Prints "some debug prefix Hello World"
However what I'm trying to do is modify this behavior throughout my entire application. I know I can manually decorate/override/import the print function in each file however I'm wondering if there is some way I can globally configure my python environment to decorate this function everywhere. The only way I can think to do this would be to edit the python source code and build the modified version.
EDIT:
Here's the behavior I wanted implemented, thank you Match for your help.
It prints out the line number and filename everywhere you call a print function within your python environment. This means you don't have to import or override anything manually in all of your files.
https://gist.github.com/MichaelScript/444cbe5b74dce2c01a151d60b714ac3a
import site
import os
import pathlib
# Big thanks to Match on StackOverflow for helping me with this
# see https://stackoverflow.com/a/48713998/5614280
# This is some cool hackery to overwrite the default functionality of
# the builtin print function within your entire python environment
# to display the file name and the line number as well as always flush
# the output. It works by creating a custom user script and placing it
# within the user's sitepackages file and then overwriting the builtin.
# You can disable this behavior by running python with the '-s' flag.
# We could probably swap this out by reading the text from a python file
# which would make it easier to maintain larger modifications to builtins
# or a set of files to make this more portable or to modify the behavior
# of more builtins for debugging purposes.
customize_script = """
from inspect import getframeinfo,stack
def debug_printer(func):
# I made this so that output always gets flushed as it won't by default
# within the environment I'm running it in. Also it will print the
# file name and line number of where the print occurs
def debug_print(*args,**kwargs):
frame = getframeinfo(stack()[1][0])
return func(f"{frame.filename} : {frame.lineno} ", flush=True,*args,**kwargs)
return debug_print
__builtins__['print'] = debug_printer(print)
"""
# Creating the user site dir if it doesn't already exist and writing our
# custom behavior modifications
pathlib.Path(site.USER_SITE).mkdir(parents=True, exist_ok=True)
custom_file = os.path.join(site.USER_SITE,"usercustomize.py")
with open(custom_file,'w+') as f:
f.write(customize_script)
You can use usercustomize script from the site module to achieve something like this.
First, find out where your user site-packages directory is:
python3 -c "import site; print(site.USER_SITE)"
/home/foo/.local/lib/python3.6/site-packages
Next, in that directory, create a script called usercustomize.py - this script will now be run first whenever python is run.
One* way to replace print is to override the __builtins__ dict and replace it with a new method - something like:
from functools import partial
old_print = __builtins__['print']
__builtins__['print'] = partial(old_print, "Debug prefix: ", flush=True)
Drop this into the usercustomize.py script and you should see all python scripts from then on being overridden. You can temporarily disable calling this script by calling python with the -s flag.
*(Not sure if this is the correct way of doing this - there may be a better way - but the main point is that you can use usercustomize to deliver whatever method you choose).
There's no real reason to define a decorator here, because you are only intending to apply it to a single, predetermined function. Just define your modified print function directly, wrapping it around __builtins__.print to avoid recursion.
def print(*args, **kwargs):
__builtins.__print(f"some debug prefix: ", flush=True, *args, **kwargs)
print("Hello world") # Prints "some debug prefix Hello World"
You can use functools.partial to simplify this.
import functools
print = functools.partial(__builtins.__print, f"some debug prefix: ", flush=True)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I want to filter the screen print by my Python program.
Ideally, it would be nice to specify a "print blacklist", such as this one.
*FutureWarning*
INFO*
When part of a screen printout matches one of the above patterns, the whole printout is filtered out.
I'm surprised no one has yet to ask this question, as I think this is extremely useful, because without it, I need to go through different types of screen printouts and deal with them accordingly. You can imagine some of them may be due to print, some due to warning, etc.
I am running my Python script from bash, so bash-based methods are welcome too!
I want to filter the screen print by my Python program.
You can use Python's logging module, routing all print and warnings output through it:
# in your main module
import logging
# -- log all output to myapp.log
logging.basicConfig(filename='myapp.log', level=logging.DEBUG)
# -- OR log all output to console
logging.basicConfig(level=logging.DEBUG)
# route all output to logging
logging.captureWarnings(True)
print = logging.info
With this add your own Filter to filter all output as per the required keywords:
# define Filter in its own module, say logfilter.py
class OutputFilter(logging.Filter):
def __init__(self, keywords, name=None):
super(OutputFilter, self).__init__(name)
self.keywords = keywords
def filter(self, record):
msg = record.getMessage()
return not any(k in msg for k in self.keywords)
# add this in your main module
from logfilter import OutputFilter
flt = OutputFilter(['*FutureWarning*', 'INFO*'])
logger = logging.getLogger() # root logger
logger.addFilter(flt)
warnLogger = logging.getLogger('py.warnings') # warnings logger
warnLogger.addFilter(flt)
(...) without it, I need to go through different types of screen printouts and deal with them accordingly.
If you can change the source code it is better to always use a module logger instead of print:
# in any module with output, right after imports
logger = logging.getLogger(__name__)
...
# instead of print
logger.info(...)
logger.error(...)
logger.debug(...)
The advantage is logging allows you very fine grained control on what to output and where, while configuring everything from a central place.
For example, while the above uses the root logger that applies to all logging output, every module of your application can have its own logger, with its specific configuration, e.g.
# somewhere in your main module
# -- basic config is to console
logging.basicConfig(level=logging.DEBUG)
# -- module A output should go into its own file
logger = logging.getLogger('path.to.module.A')
handler = logging.FileHandler(filename='myapp-A.log') # see above
logger.setHandler(handler)
logger.setLevel(logging.INFO)
# path/to/module/A.py
# -- right at the top of the module
import logging
logger = logging.getLogger(__name__)
...
# in the actual code
logger.info('info message')
This example will route all INFO messages by module A into file myapp-A.log while all other output goes to the terminal.
Note: All examples where adopted from the Python Logging Cookbook. Also check out the tutorial for more in-depth explanations.
You can bind the print variable to a custom function of yours that checks for any output you don't want to see.
Here is an example:
>>> def print(*args, **kwargs):
... import builtins
... if not any(str(s).startswith('INFO') for s in args):
... builtins.print(*args, **kwargs)
You say you're willing to do bash. You could write another script, say filter.py:
from sys import stdin
def print_filtered(line):
if line.startswith("print this"):
print(line, end='') # The line includes its own newline character
for line in stdin:
print_filtered(line)
Of course, you can put whatever filtering options you want in print_filtered(). You could even do some replacements; maybe you would want to remove the print this section of the string before you print it.
Now any program that you want to have filtered output, you can run like this:
$ python myfile.py | python filter.py
Rishav also mentioned in his comment that you could replace sys.stdout with a custom object. I don't really like that idea, but you could do that with something like this:
import sys
class FilteredPrinter(object):
def __init__(self, filtered_print, stdout):
self._filtered_print = filtered_print
self._stdout = stdout
def _write(self, string):
self._filtered_print(string, self._stdout)
def __getattr__(self, attr):
if attr == 'write':
return self._write
return getattr(self._stdout, attr)
def filtered_print(string, stdout):
if string == "\n" or string.startswith("print this"):
stdout.write(string)
sys.stdout = FilteredPrinter(filtered_print, sys.stdout)
print("print this: my text")
print("print this text")
print("Don't print this")
With this solution, you can specify whatever filters you want; you could also do this with sys.stderr. If you want to go back to the old, use sys.stdout = sys.stdout._stdout. Do be aware that the print function calls sys.stdout.write() once for each of its arguments and again for the newline character. That is, calling print("first", "second") will do this:
sys.stdout.write("first")
sys.stdout.write(" ")
sys.stdout.write("second")
sys.stdout.write("\n")
So just be sure to keep that in mind when writing your filter function.
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 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.
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)