4

OK, maybe I'm just having an off day. This seems like something a lot of people must be asking, but Google is failing me horribly. The closest thing I found was this which doesn't exactly address this issue.

At work I run Arch on my desktop (which is python 3 by default), and Debian Lenny on my company's servers (which is python 2.5). I want to write a single python script that will work in both python 2 and 3. It's a very simple script, not much to it (mostly it just calls off to git using subprocess). Everything already works in both versions of python EXCEPT for the damned print statements.

Everyone out there seems to suggest the from __future__ import print_function trick. However this was introduced in python 2.6, and I'm stuck with 2.5.

So what are my options? How can I call print in both 2.5 and 3 using the same script? I was thinking maybe some kind of wrapper function, but this might not be the most "pythonic" way of doing things. Your thoughts? And no, upgrading the server to 2.6 isn't an option.

Thanks!

Community
  • 1
  • 1
Chris Eberle
  • 47,994
  • 12
  • 82
  • 119
  • The *real* solution is to use either Python 3 or Python 2 *in both places*. Arch may have turned /usr/bin/python into Python 3, breaking all of these kinds of uses, but at least it still has Python 2 as `python2` and `python2.x` (for now, anyway.) – Thomas Wouters Jun 15 '11 at 17:04
  • OK, then maybe a side question: how do I specify that I want python 2.x to run as the interpreter? This script gets called by a lot of things (non-interactively) so just running it as `python2 scriptname` isn't an option. – Chris Eberle Jun 15 '11 at 17:07
  • The usual way: the shebang line. Find a canonical name that works on both systems (you may have to add a 'python2' symlink to the server, to point to the newest Python 2.x installation) and then make that the shebang line. – Thomas Wouters Jun 15 '11 at 17:09
  • @Thomas: if I use the shebang line, I can either run `/usr/bin/env python2` (on Arch) which basically ensures that the script won't work anywhere else, OR `/usr/bin/env python` which works everywhere, but I can't determine which version of python is being invoked. – Chris Eberle Jun 15 '11 at 17:13
  • Yes, that's what I said: because Arch decided to break `python` (by making it a version that is incompatible with what it used to be, and still is everywhere else) you can't use `python`. You have to find another canonical name that *does* work on all your systems. Arch provides a `python2` name, but older distributions do not. You would have to add it yourself. Python 3.x and 2.x are really not interchangeable. `print` is the least of the issues :P – Thomas Wouters Jun 15 '11 at 18:31
  • In case someone prefer a (not-so-pythonic) wrapper, [this](http://www.daniweb.com/software-development/python/code/217214) works. – mmoya Feb 23 '12 at 11:34
  • For posterity, the answer you're looking for doesn't need to handle the `print >>foo, 'bar'` usage, right? – shx2 Oct 26 '13 at 19:30

3 Answers3

5

print("hi") works on both py 2 and 3 without from __future__ in py 2.5

alternatively, although not recommended:

import sys
sys.stdout.write("hi")
Pwnna
  • 9,178
  • 21
  • 65
  • 91
  • 2
    That's because `("hi")` is treated as `"hi"`. Try `print("Hi", "there")`, or even `print("hi",)` – Chris Eberle Jun 15 '11 at 16:58
  • yeah exactly. It's just a set of brackets, or a tuple. – Pwnna Jun 15 '11 at 16:58
  • OK, the point being that in my old script it does things like, `print "value is", val`. If I try this using your method I get `("value is", 3)` when I wanted `value is 3`. – Chris Eberle Jun 15 '11 at 17:00
  • However I do like your suggestion to use sys.stdout.write. That may just be good enough for this task. – Chris Eberle Jun 15 '11 at 17:01
  • What isn't to recommend about using `sys.stdout.write()`? Even in just Python 2.x code it gives you much more control over what actually gets written. – Thomas Wouters Jun 15 '11 at 17:06
  • @Thomas: the main thing you lose is the implicit calling of `str`. If I do `print(3)` or `print 3` (depending on which python I'm in), it will automatically convert it to a string for me, making my code more readable. However from a functionality standpoint, it's about the same. – Chris Eberle Jun 15 '11 at 17:11
  • I don't think you lose implicit conversion.. `sys.stdout.write(3)` works as usual, though it's a lot more to type, and print is simpler. – Pwnna Jun 15 '11 at 17:15
  • @ultimatebuster: which version of python are you using? In python 2.5 I get this: `TypeError: argument 1 must be string or read-only character buffer, not int` – Chris Eberle Jun 15 '11 at 17:16
  • Yeah you're right. I was using 2.7.1. Though you can try hacking the function. Wait while i develop the lamda – Pwnna Jun 15 '11 at 17:18
  • nvm you can't change the sys.stdout.write method in 2.5... Oh well. – Pwnna Jun 15 '11 at 17:20
  • @ultimatebuster using `sys.stdout.write` did the trick in this case. I award you one internet. – Chris Eberle Jun 15 '11 at 17:24
  • 2
    As a suggestion, clarify in the your answer that `print("hi")` is not actually the function print, rather a hack. It may sound obvious to many but I think it may lead to some confusion. – Trufa Jun 15 '11 at 17:55
4

Why don't you just use the logging framework? It mitigates your issue, and is much better than print statements littered throughout the code.

Sam Dolan
  • 31,966
  • 10
  • 88
  • 84
0

This works for me:

import sys
if sys.version_info[0] == 2:
    def print_(*args):
        w = sys.stdout.write
        w( ', '.join(str(a) for a in args) )
        w( '\n' )
else:
    print_ = getattr(__builtins__, 'print')

If you need the full featured print functionality, you're better off using the print_ from six. In this case,

from six import print_
// replace all "print ..." by "print_(...)"
Oliver
  • 27,510
  • 9
  • 72
  • 103