Is this single-line syntax to read a file good practice? [duplicate] - python

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.

Related

How to tell Python to start executing code from a given line

I am completely new to Python, just learning strings and variables at the moment. I know you can put a "#" before code to comment it, but is there an option for Python to completely ignore part of the code and start working from the lines after this code?
For example:
old_price = 30
new_price = 25
difference = old_price - new_price
name = "John Smith"
age = 15
print(name, age)
I would like the code to start working from the line name="John Smith", without having to comment the first 3 lines.
You can use multiline strings to comment the whole block, not having to put # in each line:
"""
old_price = 30
new_price = 25
difference = old_price - new_price
"""
name = "John Smith"
age = 15
print(name, age)
You could define a function an call it:
# define function old()
def old():
old_price = 30
new_price = 25
difference = old_price - new_price
print (difference)
# define function string()
def string():
name = "John Smith"
age = 15
print (name, age)
string() # out: John Smith 15
I don't believe that there is and I don't think that it's actually a good idea to do so. Why would you have code you don't want to execute?
If you don't want to execute it YET, you can put code into a function and not call it.
If you're just experimenting and want to play around around you should consider things like IPython or Jupyter Notebook where you can execute code interactively
Python is a structured programming language and therefore this type of things is discouraged and not supported internally (just like goto instructions). Moreover, usually the first lines of code would be import statements that would be needed later, so you don't really want to skip them.
You SHOULD use the benefits of a structured language and put your code into functions, then you can decide later if you want to execute those functions. Another solution is to use comments (or block comments) for code that you don't want to execute currently, or for other textual lines that don't contain code.
However, just for fun, here are two ways to skip lines.
Using -x flag
You can run your program with -x flag: python -x <python_file>. This will only skip the first line. This flag is used for allowing non-Unix forms of #!cmd (as describing when running python -h).
Using another script to run your script
Python has no internal support to run from a given line, so let's cheat. We can create a script file that its only purpose is to execute another file from a given line. In this example I implemented three ways to do so (note that the exec command is bad and you should not really use that).
import os
import subprocess
import sys
import tempfile
skip_to = int(sys.argv[1])
file_path = sys.argv[2]
with open(file_path, 'r') as sourcefile:
new_source = '\n'.join(sourcefile.readlines()[skip_to:])
# Several ways to execute:
# 1. Create tempfile and use subprocess
temp = tempfile.NamedTemporaryFile(mode='w+', delete=False)
temp.write(new_source)
temp.close()
subprocess.call(['python', temp.name] + sys.argv[2:])
os.remove(temp.name)
# 2. Run from memory using subprocess and python -c
subprocess.call(['python', '-c', new_source] + sys.argv[2:])
# 3. Using exec (usually a very bad idea...)
exec(new_source)
An example code to skip:
print("first line")
print("second line")
print("third line")
from datetime import datetime
print(datetime.now())
>>python skip.py 3 main.py
>>2019-12-05 20:50:50.759259
>>2019-12-05 20:50:50.795159
>>2019-12-05 20:50:50.800118

How to save python screen output to a text file

I'd like to query items from a dict and save the printed output to a text file.
Here's what I have:
import json
import exec.fullog as e
inp = e.getdata() #inp now is a dict() which has items, keys and values.
#Query
print('Data collected on:', inp['header']['timestamp'].date())
print('\n CLASS 1 INFO\n')
for item in inp['Demographics']:
if item['name'] in ['Carly', 'Jane']:
print(item['name'], 'Height:', item['ht'], 'Age:', item['years'])
for item in inp['Activity']:
if item['name'] in ['Cycle', 'Run', 'Swim']:
print(item['name'], 'Athlete:', item['athl_name'], 'Age:', item['years'])
A quick and dirty hack to do this within the script is to direct the screen output to a file:
import sys
stdoutOrigin=sys.stdout
sys.stdout = open("log.txt", "w")
and then reverting back to outputting to screen at the end of your code:
sys.stdout.close()
sys.stdout=stdoutOrigin
This should work for a simple code, but for a complex code there are other more formal ways of doing it such as using Python logging.
Let me summarize all the answers and add some more.
To write to a file from within your script, user file I/O tools that are provided by Python (this is the f=open('file.txt', 'w') stuff.
If don't want to modify your program, you can use stream redirection (both on windows and on Unix-like systems). This is the python myscript > output.txt stuff.
If you want to see the output both on your screen and in a log file, and if you are on Unix, and you don't want to modify your program, you may use the tee command (windows version also exists, but I have never used it)
Even better way to send the desired output to screen, file, e-mail, twitter, whatever is to use the logging module. The learning curve here is the steepest among all the options, but in the long run it will pay for itself.
abarnert's answer is very good and pythonic. Another completely different route (not in python) is to let bash do this for you:
$ python myscript.py > myoutput.txt
This works in general to put all the output of a cli program (python, perl, php, java, binary, or whatever) into a file, see How to save entire output of bash script to file for more.
If you want the output to go to stdout and to the file, you can use tee:
$ python myscript.py | tee myoutput.txt
For more on tee, see: How to redirect output to a file and stdout
What you're asking for isn't impossible, but it's probably not what you actually want.
Instead of trying to save the screen output to a file, just write the output to a file instead of to the screen.
Like this:
with open('outfile.txt', 'w') as outfile:
print >>outfile, 'Data collected on:', input['header']['timestamp'].date()
Just add that >>outfile into all your print statements, and make sure everything is indented under that with statement.
More generally, it's better to use string formatting rather than magic print commas, which means you can use the write function instead. For example:
outfile.write('Data collected on: {}'.format(input['header']['timestamp'].date()))
But if print is already doing what you want as far as formatting goes, you can stick with it for now.
What if you've got some Python script someone else wrote (or, worse, a compiled C program that you don't have the source to) and can't make this change? Then the answer is to wrap it in another script that captures its output, with the subprocess module. Again, you probably don't want that, but if you do:
output = subprocess.check_output([sys.executable, './otherscript.py'])
with open('outfile.txt', 'wb') as outfile:
outfile.write(output)
You would probably want this. Simplest solution would be
Create file first.
open file via
f = open('<filename>', 'w')
or
f = open('<filename>', 'a')
in case you want to append to file
Now, write to the same file via
f.write(<text to be written>)
Close the file after you are done using it
#good pracitice
f.close()
Here's a really simple way in python 3+:
f = open('filename.txt', 'w')
print('something', file = f)
^ found that from this answer: https://stackoverflow.com/a/4110906/6794367
This is very simple, just make use of this example
import sys
with open("test.txt", 'w') as sys.stdout:
print("hello")
python script_name.py > saveit.txt
Because this scheme uses shell command lines to start Python programs, all the usual shell syntax applies. For instance, By this, we can route the printed output of a Python script to a file to save it.
I found a quick way for this:
log = open("log.txt", 'a')
def oprint(message):
print(message)
global log
log.write(message)
return()
code ...
log.close()
Whenever you want to print something just use oprint rather than print.
Note1: In case you want to put the function oprint in a module then import it, use:
import builtins
builtins.log = open("log.txt", 'a')
Note2: what you pass to oprint should be a one string (so if you were using a comma in your print to separate multiple strings, you may replace it with +)
We can simply pass the output of python inbuilt print function to a file after opening the file with the append option by using just two lines of code:
with open('filename.txt', 'a') as file:
print('\nThis printed data will store in a file', file=file)
Hope this may resolve the issue...
Note: this code works with python3 however, python2 is not being supported currently.
idx = 0
for wall in walls:
np.savetxt("C:/Users/vimal/OneDrive/Desktop/documents-export-2021-06-11/wall/wall_"+str(idx)+".csv",
wall, delimiter=",")
idx += 1
class Logger:
def __init__(self, application_log_file, init_text="Program started", print_with_time=True):
import sys
self.__output_num = 0
self.origin = sys.stdout
self.init_text = init_text
self.__init = False
self.print_with_time = print_with_time
self.log_file = application_log_file
self.data = ""
self.last_time = 0
sys.stdout = self
sys.stderr = self
def flush(self):
if self.data == "\n":
return
sys.stdout = self.origin
print(self.__create_log_text(self.data) if self.print_with_time else self.data)
with open(self.log_file, "a", encoding="utf-8") as log:
log.write(self.__create_log_text(self.data))
self.data = ""
sys.stdout = self
def __create_log_text(self, string: str):
if self.last_time == str(datetime.datetime.today())[:-7]:
return string
self.last_time = str(datetime.datetime.today())[:-7]
if not self.__init:
self.__init = True
return str(datetime.datetime.today())[:-7] + " | " + f"{self.init_text}\n"
return str(datetime.datetime.today())[:-7] + " | " + string
def write(self, data):
self.data += data

Good strategy to perform unit tests on program that prints to stdout?

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

How do I export the output of Python's built-in help() function

I've got a python package which outputs considerable help text from: help(package)
I would like to export this help text to a file, in the format in which it's displayed by help(package)
How might I go about this?
pydoc.render_doc(thing) to get thing's help text as a string. Other parts of pydoc like pydoc.text and pydoc.html can help you write it to a file.
Using the -w modifier in linux will write the output to a html in the current directory, for example;
pydoc -w Rpi.GPIO
Puts all the help() text that would be presented from the command help(Rpi.GPIO) into a nicely formatted file Rpi.GPIO.html, in the current directory of the shell
This is a bit hackish (and there's probably a better solution somewhere), but this works:
import sys
import pydoc
def output_help_to_file(filepath, request):
f = open(filepath, 'w')
sys.stdout = f
pydoc.help(request)
f.close()
sys.stdout = sys.__stdout__
return
And then...
>>> output_help_to_file(r'test.txt', 're')
An old question but the newer recommended generic solution (for Python 3.4+) for writing the output of functions that print() to terminal is using contextlib.redirect_stdout:
import contextlib
def write_help(func, out_file):
with open(out_file, 'w') as f:
with contextlib.redirect_stdout(f):
help(func)
Usage example:
write_help(int, 'test.txt')
To get a "clean" text output, just as the built-in help() would deliver, and suitable for exporting to a file or anything else, you can use the following:
>>> import pydoc
>>> pydoc.render_doc(len, renderer=pydoc.plaintext)
'Python Library Documentation: built-in function len in module builtins\n\nlen(obj, /)\n Return the number of items in a container.\n'
If you do help(help) you'll see:
Help on _Helper in module site object:
class _Helper(__builtin__.object)
| Define the builtin 'help'.
| This is a wrapper around pydoc.help (with a twist).
[rest snipped]
So - you should be looking at the pydoc module - there's going to be a method or methods that return what help(something) does as a string...
Selected answer didn't work for me, so I did a little more searching and found something that worked on Daniweb. Credit goes to vegaseat. https://www.daniweb.com/programming/software-development/threads/20774/starting-python/8#post1306519
# simplified version of sending help() output to a file
import sys
# save present stdout
out = sys.stdout
fname = "help_print7.txt"
# set stdout to file handle
sys.stdout = open(fname, "w")
# run your help code
# its console output goes to the file now
help("print")
sys.stdout.close()
# reset stdout
sys.stdout = out
The simplest way to do that is via using
sys module
it opens a data stream between the operation system and it's self , it grab the data from the help module then save it in external file
file="str.txt";file1="list.txt"
out=sys.stdout
sys.stdout=open('str_document','w')
help(str)
sys.stdout.close
The cleanest way
Assuming help(os)
Step 1 - In Python Console
import pydoc
pydoc.render_doc(os, renderer=pydoc.plaintext)`
#this will display a string containing help(os) output
Step 2 - Copy string
Step 3 - On a Terminal
echo "copied string" | tee somefile.txt
If you want to write Class information in a text file. Follow below steps
Insert pdb hook somewhere in the Class and run file
import pdb; pdb.set_trace()
Perform step 1 to 3 stated above
In Windows, just open up a Windows Command Line window, go to the Lib subfolder of your Python installation, and type
python pydoc.py moduleName.memberName > c:\myFolder\memberName.txt
to put the documentation for the property or method memberName in moduleName into the file memberName.txt. If you want an object further down the hierarchy of the module, just put more dots. For example
python pydoc.py wx.lib.agw.ultimatelistctrl > c:\myFolder\UltimateListCtrl.txt
to put the documentation on the UltimateListCtrl control in the agw package in the wxPython package into UltimateListCtrl.txt.
pydoc already provides the needed feature, a very well-designed feature that all question-answering systems should have. The pydoc.Helper.init has an output object, all output being sent there. If you use your own output object, you can do whatever you want. For example:
class OUTPUT():
def __init__(self):
self.results = []
def write(self,text):
self.results += [text]
def flush(self):
pass
def print_(self):
for x in self.results: print(x)
def return_(self):
return self.results
def clear_(self):
self.results = []
when passed as
O = OUTPUT() # Necessarily to remember results, but see below.
help = pydoc.Helper(O)
will store all results in the OUTPUT instance. Of course, beginning with O = OUTPUT() is not the best idea (see below). render_doc is not the central output point; output is. I wanted OUTPUT so I could keep large outputs from disappearing from the screen using something like Mark Lutz' "More". A different OUTPUT would allow you to write to files.
You could also add a "return" to the end of the class pydoc.Helper to return the information you want. Something like:
if self.output_: return self.output_
should work, or
if self.output_: return self.output.return_()
All of this is possible because pydoc is well-designed. It is hidden because the definition of help leaves out the input and output arguments.
Using the command line we can get the output directly and pipe it to whatever is useful.
python -m pydoc ./my_module_file.py
-- the ./ is important, it tells pydoc to look at your local file and not attempt to import from somewhere else.
If you're on the mac you can pipe the output to pbcopy and paste it into a documentation tool of your choice.
python -m pydoc ./my_module_file.py | pbcopy

How do I print to stderr in Python?

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)

Categories

Resources